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()方法。
说实话,距离上次更新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)