使用Moq 对接口进行Mock

前面我们看到的都是对一些简单方法进行测试,哪些方法都没有依赖项。如果我们哪些方法有依赖项的话,我们应该如何进行测试呢? 一个简单的方式我们是考虑它的依赖方法,并一起进行测试。(这个实际上是变成了集成测试的概念了)。如果这样的写单元测试的话,我们需要考虑的分支条件可能就会太多了。 所以我们通常会创建一个 仿造的对象和方法,并对返回值进行控制。

public class StudentService
{
    private readonly StudentSetting studentSetting;

    public StudentService(ISettingService settingService)
    {
        studentSetting = settingService.Get<StudentSetting>("student");
    }

    public int Count()
    {
        //根据 studentSetting做其它的事情, 下面的代码只是为了演示方便
        return studentSetting.MaxAge * 2;
    }
}

public interface ISettingService
{
    T Get<T>(string name);
}

public class StudentSetting
{
    public int MaxAge { get; set; }
}

public class SettingService : ISettingService
{
    public T Get<T>(string name)
    {
        //演示方便,直接返回默认实现
        return default;
    }
}

上面的代码我们的StudentService就依赖于 ISettingService了。 通过使用Moq我们可以对Count这个方法进行单元测试。 代码如下。 在使用这个之前,我们需要把Moq这个Package通过Nuget添加到我们的单元测试项目中

using FluentAssertions;
using Moq;
using Xunit;
namespace MyFirstUnitTests
{
    public class StudentServiceTest
    {
        [Fact]
        public void Count_Should_Return_Suitable_Quantity()
        {
            var studentSetting = new StudentSetting()
            {
                MaxAge = 1
            };
            //使用 new Mock创建我们需要mock的对象
            var settingService = new Mock<ISettingService>();
            //对方法进行mock, 这样我们就可以对这个方法进行控制了。 参数里面可以传 It.IsAny<string>() 也可以直接传 "student"
            settingService.Setup(it => it.Get<StudentSetting>(It.IsAny<string>())).Returns(studentSetting);
            var studentService = new StudentService(settingService.Object);

            var quantity = studentService.Count();

            //断言数量是不是一样的
            quantity.Should().Be(studentSetting.MaxAge * 2);
            //断言是否正确调用了依赖对象和方法
            settingService.Verify(x => x.Get<StudentSetting>("student"), Times.Once);
        }
    }
}

也可以用Mock.Of来写

 [Fact]
public void Count_Should_Return_Suitable_Quantity()
{
    var studentSetting = new StudentSetting()
    {
        MaxAge = 1
    };
    
    // == 后面是 返回这个方法需要返回的值
    var settingService = Mock.Of<ISettingService>(x => x.Get<StudentSetting>("student") == studentSetting);
    var studentService = new StudentService(settingService);

    var quantity = studentService.Count();

    //断言数量是不是一样的
    quantity.Should().Be(studentSetting.MaxAge * 2);
}

抽象类跟inteface的行为大部分是一致的。

下一篇:Moq的介绍
最近更新的
...