使用 Moq.AutoMock
简化 moq 的使用
Intro
之前写过一篇 Mock 框架 Moq 的使用
使用 moq 来 mock 依赖写单元测试的时候,有时候会有一些依赖会比较多的服务,构造函数爆炸,但是实际测试的方法或者逻辑可能只用到了一两个依赖,这个时候可以借助于 Moq.AutoMock
来简化代码,不用每个依赖都给一个初始化值了,来看看下面的示例吧
Sample
首先我们准备几个要测试的方法:
public interface I0
{
int GetResult();
}
public interface IA : I0
{
}
public interface IB : I0
{
}
public interface IC : I0
{
}
public interface ID : I0
{
}
file sealed class TestService
{
private readonly IA _a;
private readonly IB _b;
private readonly IC _c;
private readonly ID _d;
public TestService(IA a, IB b, IC c, ID d)
{
_a = a;
_b = b;
_c = c;
_d = d;
}
public int TestMethod1()
{
return _a.GetResult();
}
public int TestMethod2()
{
return _b.GetResult() + _c.GetResult();
}
public int TestMethod3()
{
return _d.GetResult() + 100;
}
}
TestService
中的三个测试方法就是我们要测试的对象,以第一个方法为例子,我们之前测试的话一般会怎么样去写呢,大概类似下面这样,new
一个 TestService
并将参数都 mock 填进去
[Fact]
public void TestMethod1WithoutAutoMocker()
{
var mockA = new Mock<IA>();
var service = new TestService(mockA.Object, new Mock<IB>().Object, new Mock<IC>().Object, new Mock<ID>().Object);
mockA.Setup(x => x.GetResult())
.Returns(1);
var result = service.TestMethod1();
Assert.Equal(1, result);
}
看方法的实现可以知道,我们 TestMethod1
这个方法只和 IA
service 有关系,和其他的依赖服务并没有关系,但还是得传其他的参数来获得一个 TestService
实例
使用 Moq.AutoMock
之后就可以比较方便地获取实例了,我们可以使用 GetMock<IA>
来获取一个 Mock<IA>
对象并基于此设置 mock 行为
改造后的代码如下:
[Fact]
public void TestMethod1WithAutoMocker()
{
var autoMocker = new AutoMocker();
autoMocker.GetMock<IA>().Setup(x => x.GetResult())
.Returns(1);
var service = autoMocker.CreateInstance<TestService>();
var result = service.TestMethod1();
Assert.Equal(1, result);
}
当然写法不止这一种,再看下后面两个测试方法
[Fact]
public void TestMethod2()
{
var autoMocker = new AutoMocker();
autoMocker.GetMock<IB>().Setup(x => x.GetResult())
.Returns(1);
var cMock = new Mock<IC>();
cMock.Setup(x => x.GetResult())
.Returns(1);
autoMocker.Use(cMock);
var service = autoMocker.CreateInstance<TestService>();
var result = service.TestMethod2();
Assert.Equal(2, result);
autoMocker.VerifyAll();
}
TestMethod2
会用到 IB
/IC
,我们这里设置这两个,这里的 IB
是通过 autoMocker.GetMock<IB>()
的方式来获取设置,和前面的方式一致,IC
则是我们自己通过 new Mock<IC>
来获取,之后通过 autoMocker.Use(cMock)
来注入到 autoMocker
中
autoMocker.Use
方法除了可以设置 mock 对象之外,也可以直接注入某个服务实例,比如我们也可以使用 autoMocker.Use(cMock.Object)
来注入 IC
服务
其他的和之前一样,最后调用了 VerifyAll
的方法来验证我们 mock 的设置都被调用
再来看最后一个测试方法
[Fact]
public void TestMethod3()
{
var autoMocker = new AutoMocker();
autoMocker.Use<ID>(x=> x.GetResult() == 1);
var service = autoMocker.CreateInstance<TestService>();
var result = service.TestMethod3();
Assert.Equal(101, result);
autoMocker.GetMock<ID>()
.Verify(x => x.GetResult());
}
这次我们使用 autoMocker.Use<ID>(x => x.GetResult() == 1)
来设置 ID
的 GetResult
方法返回 1
, 然后在最后通过 GetMock<ID>
获取 mock 对象并验证 GetResult
的方法调用
用了 Moq.AutoMock
之后是不是简单了一些呢,希望对大家有所帮助~~
References
https://github.com/moq/Moq.AutoMocker
https://www.nuget.org/packages/Moq.AutoMock
https://github.com/WeihanLi/SamplesInPractice/blob/master/XunitSample/MoqAutoMockTest.cs