使用Fluent assertions对复杂对象的断言,是非常方便的。
有时候我们系统里面经常会有一些将 Api 的Model对象转成Service的Dto对象的情况。而这个转型我们也需要做单元测试。并且希望下次如果有新加属性的时候。也要求能转换准确。不要漏转了。
public class MyTestClass
{
[Fact]
public void MyTest()
{
var s = new Student() { Age = 1, Name = "ab2" };
var dto = Convert(s);
//我们只要用BeEquivalentTo 它就会自动对比这个对象下面的所有属性。
dto.Should().BeEquivalentTo(s);
}
public StudentDto Convert(Student s)
{
return new StudentDto()
{
Age = s.Age,
Name = s.Name
};
}
}
public class Student
{
public int Age { get; set; }
public string Name { get; set; }
//还有很多其它的属性
}
public class StudentDto
{
public int Age { get; set; }
public string Name { get; set; }
}
两个对象属性不一致的情况。 比如说 Student有多了一个属性 AA 但是 StudtioDto没有这个属性
public class Student
{
public int Age { get; set; }
public string Name { get; set; }
public string AA { get; set; }
public string BB { get; set; }
}
public class StudentDto
{
public int Age { get; set; }
public string Name { get; set; }
}
通过 使用options.ExcludingMissingMembers()忽略不存在的成员
public class MyTestClass
{
[Fact]
public void MyTest()
{
var s = new Student()
{
Age = 1,
Name = "ab2",
};
var dto = Convert(s);
dto.Should().BeEquivalentTo(s,
options => options.ExcludingMissingMembers());
}
public StudentDto Convert(Student s)
{
return new StudentDto()
{
Age = s.Age,
Name = s.Name,
};
}
}
但是上面的例子 会有一个缺陷。就是我们新加一些属性的时候这个单元测试是会通过的。 所以我们可能需要单独排除某些属性。
[Fact]
public void MyTest()
{
var s = new Student()
{
Age = 1,
Name = "ab2",
};
var dto = Convert(s);
dto.Should().BeEquivalentTo(s,
options => options.Excluding(x => x.AA)//排除 AA
.Excluding(x => x.BB));//排除 BB
//上面的断言还可以改成,
dto.Should().BeEquivalentTo(s,
options => options.Excluding(x => x.SelectedMemberPath == "AA" | x.SelectedMemberPath == "BB"));
}
假设有一些属性名是Date结尾 我们转型或者做一些操作允许它的时间出现一定的变化(比如说转时区等).这样比较的时候我们就需要对这个字段进行特殊判断了。
[Fact]
public void MyTest()
{
var s = new Student()
{
Age = 1,
Name = "ab2",
BirthDate = DateTime.Now
};
var dto = Convert(s);
dto.Should().BeEquivalentTo(s,
options => options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation, 4000))
.When(info => info.SelectedMemberPath.Contains("Date")));
}
public StudentDto Convert(Student s)
{
return new StudentDto()
{
Age = s.Age,
Name = s.Name,
BirthDate = s.BirthDate.AddSeconds(3)
};
}
}
public class Student
{
public int Age { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
public class StudentDto
{
public int Age { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}