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



我有一个用户界面,让我们称之为IUser。 这有两种实现方式:AdminUser and NormalUser

现在,我正在尝试通过单元测试(模拟)使用这些用户类。

我模拟界面如下:

var mockUser = new Mock<IUser>();
mockUser.get("username");

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

它永远不会停留在调试点,也没有来自 mockUser 实例的线索。

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

提前谢谢。

创建一个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);
}

IPostalCodeRegexProvider的实施可以是任何东西。它可以调用数据库,也可以是硬编码的。

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

如果我想测试ValidatePostalCode在返回 null 时返回trueIPostalCodeRegexProvider.GetPostalCode,那么我需要确保它将返回 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"));
}

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

您也可以考虑使用"测试替身"。您只需创建一个实现接口的简单类,而不是使用 Moq。例如,我对 Moq 所做的我也可以这样做:

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更容易理解。有时模拟的设置可能会变得复杂且难以阅读和调试,但一个简单的类可以很好地完成这项工作,甚至更好。

为了测试实际的实现,你需要初始化实际的实现,即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);
}

参考最小起订量快速入门,以更好地了解如何使用起订量

相关内容

最新更新