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