我正在创建几个单元测试,我想在其中验证是否使用了我期望其属性的参数调用了一个方法。
因此,给出了一个非常简单的系统:
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()
属性设置为false时是否调用了Employee.IsEmployed
方法。所以这是我认为应该完成同一件事的两个测试用例。
[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()
方法。
答案 0 :(得分:1)
说实话,距离我上次使用moq
源代码更新的时间已经超过2年了。 Verify
和VerifyAll
均基于捕获到的所有伪实例调用(包括参数)。
Verify
将查找方法/属性调用并验证捕获的调用(及其捕获的参数),而VerifyAll
将采用所有设置方法,并且与Verify
方法相同
由于捕获的参数是ByRef
参数,并且如果最后一段仍然有用,则可以通过在调用robert.IsEmployed = true;
/ Verify
之前添加VerifyAll
来导致UT失败:
[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();
}
我认为过去我回答过类似的问题(有更多示例),因此解决该问题的方法是Setup
和Callback
之间的组合,因为我不喜欢使用{ {1}}模式:
VerifyAll
答案 1 :(得分:1)
这是moq
中的预期行为,因为通过调用比较捕获的参数,使用Equals
而不是使用值来标识。一旦更改了捕获的参数,实际上就可以直接更改调用。然后,当您确认这些对象不再相同时。正如@Old Fox所提供的一种解决方案,我将再添加一种。您可以使用Verify()
而不是VerifyAll()
,不同之处在于第一个将仅检查标记为Verifiable()
的设置。在您的情况下,如下所示:
[Test]
public void TestViaSetupVerifyAll()
{
//Arrange
Mock<IDataStore> dataStore = new Mock<IDataStore>();
dataStore
.Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)))
.Verifiable();
var robert = new Employee { IsEmployed = true };
//Act
FireEmployee(dataStore.Object, robert);
//Assert
dataStore.Verify();
}
如果将设置标记为Verifiable()
,则可以使用您实际期望的对象状态捕获特定的调用。