模拟单元测试 - 获取实现接口的类的详细信息

lea*_*arn 2 c# unit-testing moq mocking

我有一个用户界面可以调用它IUser.这有两个实现:AdminUser and NormalUser.

现在,我试图通过单元测试(Mocking)来使用这些用户类.

我按如下方式模拟界面:

var mockUser = new Mock<IUser>();

mockUser.get("username");
Run Code Online (Sandbox Code Playgroud)

我在整个类中添加了breakkpoints,但我不确定接口的哪个实例被调用,即AdminUser or NormalUser.

它永远不会停留在调试点,也不会从mockUser实例中找到线索.

如何获取mockUser mock实例调用的类的详细信息?

提前致谢.

Sco*_*nen 5

创建一个Mock<IUser>实际创建的实现IUser.因此,它无法帮助您测试任何实际的实现.

使用这样的Mock工作:

假设我有这个类和接口.该类验证邮政编码是否对某个国家/地区有效.它取决于为给定国家/地区提供正则表达式模式的另一个接口.

public class PostalCodeValidator
{
    private readonly IPostalCodeRegexProvider _regexProvider;

    public PostalCodeValidator(IPostalCodeRegexProvider regexProvider)
    {
        _regexProvider = regexProvider;
    }

    public bool ValidatePostalCode(string postalCode, string countryCode)
    {
        var regex = _regexProvider.GetPostalCodeRegex(countryCode);
        if (string.IsNullOrEmpty(regex)) return true;
        return Regex.IsMatch(postalCode, regex);
    }
}

public interface IPostalCodeRegexProvider
{
    string GetPostalCodeRegex(string countryCode);
}
Run Code Online (Sandbox Code Playgroud)

实施IPostalCodeRegexProvider可以是任何事情.它可以调用数据库,它可以是硬编码的.

但是,当我写单元测试PostalCodeValidator,我明确地想要测试真正落实IPostalCodeRegexProvider.我想让我的IPostalCodeValidator回报完全符合我的要求,这样我才能确保PostalCodeValidator有效.我只是在测试PostalCodeValidator.

如果我想测试ValidatePostalCode返回trueIPostalCodeRegexProvider.GetPostalCode返回null,然后我需要确保它返回null.这就是Mock进来的地方.

它允许我轻松创建一个IPostalCodeRegexProvider始终返回null的实现,因此我可以测试ValidatePostalCode该null的用途.

[TestMethod]
public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
    var mock = new Mock<IPostalCodeRegexProvider>();
    mock.Setup(x => x.GetPostalCodeRegex(It.IsAny<string>())).Returns(default(string));
    var subject = new PostalCodeValidator(mock.Object);
    Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}
Run Code Online (Sandbox Code Playgroud)

无论测试的主题是-在这种情况下PostalCodeValidator,或者在您的情况AdminUserNormalUser-这就是你将创造什么样的一个实例.如果这些类依赖于其他接口,那么您可以Mock为每个接口创建一个.

您还可以考虑使用"测试双倍".您只需创建一个实现接口的简单类,而不是使用Moq.例如,我用Moq做的事情也可以这样做:

public class PostalCodeRegexProviderThatReturnsNull : IPostalCodeRegexProvider
{
    public string GetPostalCodeRegex(string countryCode)
    {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在单元测试看起来像这样:

public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
    var regexProvider = new PostalCodeRegexProviderThatReturnsNull();
    var subject = new PostalCodeValidator(regexProvider);
    Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}
Run Code Online (Sandbox Code Playgroud)

这通常比使用a更容易理解Mock.有时,模拟的设置会变得复杂,难以阅读和调试,但是简单的类可以完成这项工作,甚至更好.