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。只需创建类的直接实例并对其调用方法。