• 如何使用Moq.AutoMock简化moq的使用
  • 发布于 2个月前
  • 153 热度
    0 评论
背景
使用 moq 来 mock 依赖写单元测试的时候,有时候会有一些依赖会比较多的服务,构造函数爆炸,但是实际测试的方法或者逻辑可能只用到了一两个依赖,这个时候可以借助于 Moq.AutoMock 来简化代码,不用每个依赖都给一个初始化值了,来看看下面的示例吧!

例子
首先我们准备几个要测试的方法:
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;
    // 堆代码 duidaima.com
    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 之后是不是简单了一些呢,希望对大家有所帮助~~
用户评论