在前面我们也有看过类似如下的代码。这是一个基本类型的参数,我们可以方便的直接写在Verify里面。
settingService.Verify(it => it.GetStudentSetting("ex"), Times.Once);
但是如果是一个自定义的对象,我们也是可以使用It.Is来验证参数
public class StudentController
{
private readonly IStudentService studentService;
public StudentController(IStudentService studentService)
{
this.studentService = studentService;
}
public void Add(StudentModel studentModel)
{
var student = new Student()
{
Birthday = studentModel.Birthday,
Name = studentModel.Name
};
//还有其它的代码等.
studentService.Add(student);
}
}
public interface IStudentService
{
void Add(Student student);
}
public class StudentModel
{
public DateTime Birthday { get; set; }
public string Name { get; set; }
}
public class Student
{
public DateTime Birthday { get; set; }
public string Name { get; set; }
}
[Fact]
public void Add_Should_Invoke_Service_To_Add()
{
var service = new Mock<IStudentService>();
var controller = new StudentController(service.Object);
var model = new StudentModel();
controller.Add(model);
service.Verify(it => it.Add(It.Is<Student>(x => x.Name == model.Name && x.Birthday == model.Birthday)), Times.Once);
}
上面的有一个缺点就是如果属性很多的话我们写起来会比较麻烦。然后也不清楚具体是哪一个参数没有传对。 如果student的参数比较多的话,这个也会变得不易读了。
using Moq;
using System.Collections.Generic;
//我们故意将命名空间设成这个。因为这个是每个单元测试都要用的。
namespace Xunit
{
public class ArgumentCaptor<T>
{
public T Value { get; private set; }
public List<T> Values { get; private set; } = new List<T>();
public T Capture()
{
return It.Is<T>(t => SaveValue(t));
}
private bool SaveValue(T t)
{
Value = t;
Values.Add(t);
return true;
}
}
}
为了能方便的使用FluentAssertions.我们设计了一个类叫 ArgumentCaptor 然后上面的单元测试代码就可以变成如下的形式了
[Fact]
public void Add_Should_Invoke_Service_To_Add()
{
var service = new Mock<IStudentService>();
var controller = new StudentController(service.Object);
var model = new StudentModel();
controller.Add(model);
var argStudent = new ArgumentCaptor<Student>();
service.Verify(it => it.Add(argStudent.Capture()), Times.Once);
argStudent.Value.Name.Should().Be(model.Name);
argStudent.Value.Birthday.Should().Be(model.Birthday);
}
代码是变多了。但是更易读了。
还有一个比较方面的是写在Callback里面。 但是跟我们UnitTest的风格不太符合了。