Moq-检查对具体类的方法调用
本文关键字:方法 调用 检查 Moq- | 更新日期: 2023-09-27 18:22:13
下面是一个非常简单的例子,说明我要做的事情:
public class Bar
{
public void SomeMethod(string param)
{
//whatever
}
}
public interface IBarRepository
{
List<Bar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<Bar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
在我的测试中,我模拟IBarRepository返回单元测试中定义的具体List,并将模拟的存储库实例传递给FooService构造函数。
我想在FooService方法GetBars中验证是否为从存储库返回的每个Bars调用了SomeMethod。我正在使用Moq。有没有什么方法可以做到这一点,而不嘲笑返回的酒吧列表(如果可能的话),也不必在酒吧里放一些粗鲁的旗帜(恶心)?。
我正在学习DDD书中的一个例子,但我开始觉得它有味道,因为我在测试实现时遇到了挑战。。。。
修订。。。通过:
public class Bar
{
public virtual void SomeMethod(string param)
{
//whatever
}
}
public interface IBarRepository
{
List<Bar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<Bar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
[TestMethod]
public void Verify_All_Bars_Called()
{
var myBarStub = new Mock<Bar>();
var mySecondBarStub = new Mock<Bar>();
var myBarList = new List<Bar>() { myBarStub.Object, mySecondBarStub.Object };
var myStub = new Mock<IBarRepository>();
myStub.Setup(repos => repos.GetBarsFromStore()).Returns(myBarList);
var myService = new FooService(myStub.Object);
myService.GetBars();
myBarStub.Verify(bar => bar.SomeMethod(It.IsAny<string>()), Times.Once());
mySecondBarStub.Verify(bar => bar.SomeMethod(It.IsAny<string>()), Times.Once());
}
请注意对类Bar的轻微更改(SomeMethod()是虚拟的)。一个变化,但不涉及标志…:)
现在,就更广泛的设计而言,你的酒吧正在发生一些变化(无论"SomeMethod()"实际做了什么)。最好的方法可能是验证从FooService.GetBars()返回的每个Bar上是否发生了这种突变。也就是说,设置存储库存根以返回一些Bar,然后验证SomeMethod()执行的任何突变是否发生。毕竟,您可以控制将返回的Bars,这样您就可以设置它们的pre-SomeMethod()状态,然后检查它们的post-SomeMethod()状态。
如果我在编写这些类时考虑到单元测试,我可能会让类Bar
实现接口IBar
并在我的服务中使用该接口,或者在Bar
中使SomeMethod
虚拟化。
理想情况下是这样的:
public interface IBar
{
void SomeMethod(string param);
}
public class Bar : IBar
{
public void SomeMethod(string param) {}
}
public interface IBarRepository
{
List<IBar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<IBar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
然后我的单元测试将如下所示:
[Test]
public void TestSomeMethodCalledForEachBar()
{
// Setup
var barMocks = new Mock<IBar>[] { new Mock<IBar>(), new Mock<IBar>() };
var barObjects = barMocks.Select(m => m.Object);
var repoList = new List<IBar>(barsObjects);
var repositoryMock = new Mock<IBarRepository>();
repositoryMock.Setup(r => r.GetBarsFromStore()).Returns(repoList);
// Execute
var service = new FooService(repositoryMock.Object);
service.GetBars();
// Assert
foreach(var barMock in barMocks)
barMock.Verify(b => b.SomeMethod("someValue"));
}