Verify() 和 Setup()...VerifyAll() 之间的最小起订量差异

Fde*_*gon 5 c# nunit unit-testing assert moq

我正在创建几个单元测试,我想验证是否使用我期望的属性调用方法。

因此,鉴于这个非常简单的系统:

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;
}
Run Code Online (Sandbox Code Playgroud)

我想验证该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();
}
Run Code Online (Sandbox Code Playgroud)

给定系统的当前代码,两个测试都按预期通过。

现在说另一个开发人员不小心移动Employee.IsEmployed = false;DataStore.UpdateEmployee()方法after 的设置。现在在这种情况下,我希望我的测试失败,因为该员工不会在数据库中被标记为失业。

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

    employee.IsEmployed = false;

    return employee;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我运行测试时:

TestViaVerify 通过

TestViaSetupVerifyAll失败

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

有没有办法只使用验证方法来完成我想要的?并且不必进行设置... VerifyAll?如果没有,我就采用TestViaVerifyAll()方法。

Old*_*Fox 1

说实话,距离上次更新moq源代码已经过去两年多了。和Verify都是VerifyAll基于捕获假实例的每次调用(包括参数)。

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

由于捕获的参数是参数,并且如果最后一段仍然相关,您只需在调用/之前ByRef添加即可导致 UT 失败:robert.IsEmployed = true;VerifyVerifyAll

[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();
}
Run Code Online (Sandbox Code Playgroud)

我认为在过去我回答过类似的问题(有更多的例子),我解决这个问题的方式是 和 之间的组合,Setup因为Callback我不喜欢使用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);
Run Code Online (Sandbox Code Playgroud)