c# - 如何使用在方法中具有依赖性的最小起订量对类进行单元测试?

标签 c# unit-testing moq

我想对验证用户身份的类 AuthClient(使用 Moq)进行单元测试。

问题是我的 AuthenticationService 依赖项没有注入(inject)到类中。我对如何在不注入(inject)依赖项的情况下测试流程感到有点困惑。

[TestClass] 
public class AuthClient 
{
    string Dictionary<string, IList<UserPermissions> _userPermissions;

    User Login(string username, string password)
    {
        IAuthenticationService authenticationService = new AuthenticationService();
        User user = authService.Login(username, password);

        IAuthorizationService authorizationService = new AuthorizationService();
        var permissions = authorizationService.GetPermissions(user);
        _userPermissions.Add(user.Username, permissions);

        return user;
    }
}

我当前的单元测试代码如下所示:

public class UnitTestClass
{
    public string UserName {get;set;}
    public string Password {get;set;}

    [TestInitialize]
    public void Setup() 
    {
        UserName = "test";
        Password = "test123";
    }

    [TestMethod]
    public void When_ValidUserCredentials_Expect_UserIsNotNull()
    {
        var mockAuthenticationService = new Mock<IAuthenticateService>();
        mockAuthenticationService.Setup(m => m.Login(ValidUserName, ValidPassword)).Returns(ValidUserDto);

        var mockAuthorizationService = new Mock<IAuthorizeService>();
        mockAuthorizationService.Setup(m => m.GetAllPermissions(ValidUserId)).Returns(ValidPermissionList);

        var authClient = new Mock<AuthClient>();
        // I want to use mock dependencies here to test flow against mock data
        User user = authClient.Login(UserName, Password); 

        Assert.IsNotNull(user);
    }
}

有什么地方出了问题吗?

最佳答案

Moq 允许您测试依赖于其他类/对象(以及许多其他事物)的类。 注意:Moq 不是 IOC 容器。

在您的 AuthClient 类中,您不允许它被赋予任何依赖项,而是实例化它自己的,例如

IAuthenticationService authenticationService = new AuthenticationService();

相反,您需要在 AuthClient 类上定义一个构造函数,它接受两个对象(它应该依赖于这两个对象),还有其他方法可以“注入(inject)”依赖项,但现在我们将使用构造函数注入(inject) (good example)

例如

public class AuthClient 
{
    string Dictionary<string, IList<UserPermissions> _userPermissions;
    private IAuthenticationService _authenticationService;
    private IAuthorizationService _authorizationService;

    public AuthClient(IAuthenticationService authenticationService, IAuthorizationService authorizationService)
    {
        _authenticationService = authenticationService;
        _authorizationService = authorizationService;
    }

    User Login(string username, string password)
    {
        User user = _authenticationService.Login(username, password);

        var permissions = _authorizationService.GetPermissions(user);
        _userPermissions.Add(user.Username, permissions);

        return user;
    }
}

现在,每次你想使用这个类时,你都必须告诉它应该使用哪个授权服务和身份验证服务。您已经将 AuthClient 与特定实现分离 - 现在它非常可测试和可重用(如果您想创建一个新的 AuthenticationService 来做一些与旧的完全不同的事情,您只需要编写一个实现 IAuthenticationService 的类!)

您现在必须在每次要使用它时包含 AuthClient 的依赖项(将其提供给它的构造函数)。 您应该阅读更多关于依赖注入(inject)和 IOC(控制反转)的内容(这是一个非常大的主题,有很多不同的方法可以做同样的事情),google 是您的 friend 。

测试类现在应该是这样的:

public class UnitTestClass
{
    public string UserName {get;set;}
    public string Password {get;set;}

    [TestInitialize]
    public void Setup() 
    {
        UserName = "test";
        Password = "test123";
    }

    [TestMethod]
    public void When_ValidUserCredentials_Expect_UserIsNotNull()
    {
        var mockAuthenticationService = new Mock<IAuthenticateService>();
        mockAuthenticationService.Setup(m => m.Login(ValidUserName, ValidPassword)).Returns(ValidUserDto);

        var mockAuthorizationService = new Mock<IAuthorizeService>();
        mockAuthorizationService.Setup(m => m.GetAllPermissions(ValidUserId)).Returns(ValidPermissionList);

        // Here we are "injecting" the dependencies into the AuthClient
        var authClient = new AuthClient(mockAuthenticationService.Object, mockAuthorizationService.Object);
        // This service call will now use the supplied (mocked) services above
        User user = authClient.Login(UserName, Password); 

        Assert.IsNotNull(user);
    }
}

关于c# - 如何使用在方法中具有依赖性的最小起订量对类进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31023571/

相关文章:

c# - 模型绑定(bind)与史蒂夫桑德森的 BeginCollectionItem

python - 单元测试面向方面的功能

c# - Moq It.IsSubtype 没有隐式引用转换

asp.net - 使用 DI DbContext 和使用 LINQ 的模型对 Controller 进行单元测试 - EF Core 2

c# - BOTS框架,空属性无法加密

c# - 如何使用 XML-RPC 在 Python 和 C# 之间进行通信?

c# - 如何使用 DTW 算法实现修剪策略?

java - WSUnit 死了吗?还有什么选择?

python - 在 Python 中进行测试 - 如何在使用 unittest 进行测试时使用 assertRaises?

.net - 如何起订功能