c# - Verify() 和 Setup()...VerifyAll() 之间的最小起订量区别

标签 c# unit-testing nunit moq assert

我正在创建几个单元测试,我想在其中验证是否使用具有我期望的属性的参数调用了一个方法。

所以给定这个非常简单的系统:

public class Employee
{
    public bool IsEmployed { get; set; }
}

public class DataStore
{
    public void UpdateEmployee(Employee obj)
    {
        // Save in DB
    }
}

public interface IDataStore
{
    void UpdateEmployee(Employee employee);
}

public Employee FireEmployee(IDataStore dataStore, Employee employee)
{
    employee.IsEmployed = false;

    dataStore.UpdateEmployee(employee);

    return employee;
}

我想验证 DataStore.UpdateEmployee() 方法在 Employee.IsEmployed 属性设置为 false 时被调用。所以这里有两个测试用例,我认为它们应该完成同样的事情。

[Test]
public void TestViaVerify()
{
    //Arrange
    Mock<IDataStore> dataStore = new Mock<IDataStore>();
    var robert = new Employee { IsEmployed = true };

    //Act
    FireEmployee(dataStore.Object, robert);

    //Assert
    dataStore.Verify(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)), Times.Once);
}

[Test]
public void TestViaSetupVerifyAll()
{
    //Arrange
    Mock<IDataStore> dataStore = new Mock<IDataStore>();
    dataStore.Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)));

    var robert = new Employee { IsEmployed = true };

    //Act
    FireEmployee(dataStore.Object, robert);

    //Assert
    dataStore.VerifyAll();
}

鉴于系统的当前代码,两个测试均按预期通过。

现在假设另一个开发人员出现并意外地将 Employee.IsEmployed = false; 的设置移动到 DataStore.UpdateEmployee() 方法之后。现在在那种情况下,我希望我的测试失败,因为员工不会在数据库中被标记为失业。

public Employee FireEmployee(IDataStore dataStore, Employee employee)
{
    dataStore.UpdateEmployee(employee);

    employee.IsEmployed = false;

    return employee;
}

现在当我运行测试时:

TestViaVerify 通过

TestViaSetupVerifyAll 失败

我原以为它们都会失败,但看起来对于 TestViaVerify() 方法,方法中的 lambda 在测试结束时执行,其中 Employee.IsEmployed 已设置为 false。

有没有办法只使用 Verify 方法来完成我想要的?而不必执行设置...VerifyAll?如果没有,我将采用 TestViaVerifyAll() 方法。

最佳答案

老实说,距离我上次更新 moq 源代码已经两年多了。 VerifyVerifyAll 都是基于对假实例的每次调用都被捕获(包括参数)。

Verify 将查找方法/属性调用并验证捕获的调用(及其捕获的参数),而 VerifyAll 将采用所有设置方法并执行与验证方法。

由于捕获的参数是 ByRef 参数,如果最后一段仍然相关,您可以通过在调用 之前添加 robert.IsEmployed = true; 来导致您的 UT 失败code>验证/VerifyAll:

[Test]
public void TestViaVerify()
{
    ....
    robert.IsEmployed = true; // will make this UT to failed
    //Assert
    dataStore.Verify(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)), Times.Once);
}

[Test]
public void TestViaSetupVerifyAll()
{
    ....
    robert.IsEmployed = true; // will make this UT to failed
    //Assert
    dataStore.VerifyAll();
}

我认为过去我回答过类似的问题(有更多示例),我解决这个问题的方法是 SetupCallback 之间的组合,因为我不知道不喜欢使用 VerifyAll 模式:

....
var invokedCorrectly = false;
dataStore.Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)))
         .Callback<Employee>(x=> invokedCorrectly = true);

//Act
FireEmployee(dataStore.Object, robert);

//Assert
Assert.IsTrue(invokedCorrectly);

关于c# - Verify() 和 Setup()...VerifyAll() 之间的最小起订量区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54797998/

相关文章:

c# - 最小起订量测试无效方法

c# - 没有 Bootstrap 的 Blazor Material

c# - 如何发现哪个测试单元检查了哪些代码行?

c# - 如何获取从表单/字符串中获取的值的系统类型?

python,在同一个函数中 stub 随机性两次

wcf - 如何对 WCF .SVC 文件进行单元测试

java - 如何在android中使用实际的HttpURLConnection进行单元测试?

c# - NUnit:在单个测试中运行多个断言

c# - 母版页中我的网络内容表单中的谷歌地图

c# - 绑定(bind)多功能 WPF DataGrid