我有一个可以进行两次提交的方法——这里是它的简化版本:
public void methodA(objectA objA, List<objectB> objB)
{
_repoA.AddAsync(objA);
var id = _repoA.SaveChanges();
if(id > 0) {
foreach (var ob in objB)
{
ob.objAId = id;
_repoB.AddRange(ob);
}
_repoB.SaveChanges();
}
}
我如何在单元测试中获取/设置id
,以查看我的列表的objAId
是否已设置,并且它实际上包含两个对象-现在,由于我无法在第一次提交中设置/获取id
,我的测试失败:
[Fact]
public async void test()
{
var objA = new ObjA(null);
var objB = new List<ObjB>
{
new ObjB(null, null, "Test"),
new ObjB(null, null, "Test2")
});
var result = await _sut.methodA(objA, objB);
Assert.NotNull(result);
_mockFieldRepository.Verify(x => x.InsertAsync(It.IsAny<MyObjectA>()), Times.Once);
_mockFieldOptionRepository.Verify(x => x.InsertAsync(It.IsAny<MyObjectB>()), Times.Once); //fails here
_mockFieldOptionRepository.Verify(x => x.InsertAsync(It.Is<MyObjectB>(p => p.Id > 0 && p.objAId == objA.Id))); //fails here
}
注意:我不得不猜测你的一些测试设置和接口被嘲笑了,所以我的答案可能不完全正确
如果我们采用您的原始代码,似乎没有设置模拟来配置代码预期发生的情况。您只是使用验证来确保某些事情确实发生了。
因此,我们需要做的第一件事是配置mock,使隐含的mock成为错误,并设置期望值。
_mockFieldRepository = new Mock<IFieldRepository>(MockBehaviour.Strict);
您现在会发现,由于SaveChanges和AddRange不是安装程序,因此会出现测试错误。这很好。所以也要为它们添加设置。
_mockFieldRepository.Setup(x => x.SaveChanges();
_mockFieldRepository.Setup(x => x.AddRange(It.IsAny<MyObjectA>());
_mockFieldRepository.Setup(x => x.InsertAsync(It.IsAny<MyObjectA>()));
_mockFieldOptionRepository.Setup(x => x.InsertAsync(It.IsAny<MyObjectB>()));
_mockFieldOptionRepository.Setup(x => x.InsertAsync(It.Is<MyObjectB>(p => p.Id > 0 && p.objAId == objA.Id)));
使用它是个好主意>在设置过程中,或者对于简单的参数(整数、字符串等(,只需传递预期值,而不是It.Is.
在我看来,验证不是很好,因为它。IsAny<gt;((的意思是,你不在乎这个函数是如何被调用的,所以你应该使用It.is(就像第三个设置一样(来100%确定你希望传递给方法的参数就是你得到的参数。