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

C# 模拟单元测试-获取实现接口的类的详细信息,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,我有一个用户界面,我们可以称之为IUser。 这有两种实现:AdminUser和NormalUser 现在,我正试图通过单元测试(Mocking)使用这些用户类 我模拟界面如下: var mockUser = new Mock<IUser>(); mockUser.get("username"); var mockUser=new Mock(); mockUser.get(“用户名”); 我在整个类中添加了breakkpoints,但我不确定调用的是接口的哪个实例,即Admin

我有一个用户界面,我们可以称之为
IUser
。 这有两种实现:
AdminUser和NormalUser

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

我模拟界面如下:

var mockUser = new Mock<IUser>();

mockUser.get("username");
var mockUser=new Mock();
mockUser.get(“用户名”);
我在整个类中添加了breakkpoints,但我不确定调用的是接口的哪个实例,即
AdminUser还是NormalUser

它从不在调试点停止,也不会从mockUser实例中得到任何线索

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


提前谢谢

为了测试实际实现,您需要初始化实际实现,即
new AdminUser()

比如说

[TestMethod]
public void TestAdminUser {
    //Arrange
    IUser admin = new AdminUser();
    //...set any necessary members relevant to the test

    //Act
    //...invoke member to be tested

    //Assert
    //...verify actual to expected behavior

}
如果任何一个实现都有外部依赖项,那么您将模拟这些(依赖项)并注入它们

如果类依赖于
IUser

public class SomeClass {
    private readonly IUser user;

    public SomeClass(IUser user) {
        this.user = user;
    }

    //...
}
如果您想测试该类,那么您就有理由模拟
IUser
进行独立的单元测试

[TestMethod]
public void TestSomeClass {
    //Arrange
    var username = "dummy";
    var expected = "some value";
    var mock = new Mock<IUser>();
    //...set any necessary members relevant to the test
    mock.Setup(_ => _.username).Returns(username);

    var subject = new SomeClass(mock.Object);

    //Act
    //...invoke member to be tested
    var actual = subject.SomeMethod();

    //Assert
    //...verify actual to expected behavior
    Assert.AreEqual(actual, expected);
}
[TestMethod]
公共void测试类{
//安排
var username=“dummy”;
var expected=“some value”;
var mock=new mock();
//…设置与测试相关的任何必要成员
mock.Setup(=>880;.username).Returns(username);
var subject=newsomeclass(mock.Object);
//表演
//…调用要测试的成员
var-actual=subject.SomeMethod();
//断言
//…验证实际到预期的行为
断言.AreEqual(实际、预期);
}
参考以更好地了解如何使用Moq

创建一个
模拟
实际上创建了一个
IUser
的新实现。因此,它不会帮助您测试任何实际实现

使用
Mock
的工作原理如下:

public class PostalCodeRegexProviderThatReturnsNull : IPostalCodeRegexProvider
{
    public string GetPostalCodeRegex(string countryCode)
    {
        return null;
    }
}
public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
    var regexProvider = new PostalCodeRegexProviderThatReturnsNull();
    var subject = new PostalCodeValidator(regexProvider);
    Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}
假设我有这个类和接口。该类验证邮政编码是否对国家/地区有效。它取决于为给定国家/地区提供正则表达式模式的另一个接口

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);
}
IPostalCodeRegexProvider
的实现可以是任何东西。它可以调用数据库,也可以硬编码

但是,当我为
PostalCodeValidator
编写单元测试时,我明确不想测试
IPostalCodeRegexProvider
的真正实现。我想让
IPostalCodeValidator
准确返回我想要的内容,这样我就可以确保
PostalCodeValidator
工作正常。我只是在测试
postalocadevalidator

如果我想测试
ValidatePostalCode
IPostalCodeRegexProvider.GetPostalCode
返回null时返回
true
,那么我需要确保它将返回null。这就是
Mock
的用武之地

它允许我轻松创建一个总是返回null的
IPostalCodeRegexProvider
实现,因此我可以测试
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"));
}
现在,单元测试如下所示:

public class PostalCodeRegexProviderThatReturnsNull : IPostalCodeRegexProvider
{
    public string GetPostalCodeRegex(string countryCode)
    {
        return null;
    }
}
public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
    var regexProvider = new PostalCodeRegexProviderThatReturnsNull();
    var subject = new PostalCodeValidator(regexProvider);
    Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}

这通常比使用
Mock
更容易理解。有时,mock的设置可能会变得复杂,难以阅读和调试,但是一个简单的类也可以做得同样好,甚至更好。

两个类都没有被调用。Moq使用接口创建自己的实现代理,并允许您配置行为。这似乎是一个错误。您试图实现的最终目标是什么?您是在测试实现还是依赖于实现的主题?嗨,Nkosi,是的,我正在测试接口的各个实现。你知道我该怎么做吗?顺便说一句,感谢您让我知道XY问题:)为了测试实际实现,您需要初始化实际实现,即
new AdminUser()
。如果任何一个实现都有外部依赖项,那么您将模拟这些(依赖项)并注入它们。如果一个类依赖于一个
IUser
,并且您想要测试该类,那么您就有理由模拟
IUser
进行独立的单元测试。如果您想要对单个类进行文本处理,那么您不需要使用mock和interface。只需创建类的直接实例并对其调用方法。