为大量业务对象类(超过400个)设计一些XUnit测试。将会有很多重复的代码,因此采用DRY原理,我们有很多选择,可以将代码抽象和封装到共享的类库中。
将测试创建为扩展方法(选项2),是否违反了单元测试的原则,即提示仅测试较小的特定单元。现在,小型测试链可以分组为父级测试吗?
是否还有其他设计体系结构模式可以使共享库重用于域实体的通用测试?
下面的代码演示了这两个选项。请注意,Helper类将位于与UnitTest类(Test_Person)项目分开的另一个Class Lib项目中。
using Xunit;
namespace CCTools.UnitTest.Main.XUnit.UnitTestPatterns
{
public class Test_Person
{
/// <summary>
/// Use Extension methods, quick to code and easy to read.
/// </summary>
[Fact]
public static void Test_Stuff_UseExtenions_A()
{
Person p = new Person();
//Do lots of other config and tests...
p.Test_IncreaseCreditRating(187);
p.IsManager = true;
p.Test_CreditRating_is_valid_for_manager();
}
[Fact]
public static void Test_Stuff_UseExtenions_B()
{
Person p = new Person();
//Do lots of other config and tests...
p.Test_IncreaseCreditRating(59);
p.Test_CreditRating_is_valid_for_manager();
}
/// <summary>
/// Use traditional Helper methods, not as easy to read or code.
/// </summary>
[Fact]
public static void Test_Stuff_UseHelper_A()
{
Person p = new Person();
//Do lots of other config and tests...
PersonUniTestHelper.Test_IncreaseCreditRating(p, 10);
p.IsManager = true;
PersonUniTestHelper.Test_CreditRating_is_valid_for_manager(p);
}
}
/// <summary>
/// Extension methods, which makes coding far easier on the eye and one is able to locate all methods
/// using intellisense at a glance.
/// </summary>
public static class PersonUniTestExtensionMethods
{
public static void Test_IncreaseCreditRating(this Person person, int creditRating)
{
person.IncreaseCreditRating(creditRating);
if (creditRating >= 100) Assert.Equal(100 * 1000, person.CreditLimit);
else Assert.Equal(creditRating * 1000, person.CreditLimit);
}
public static void Test_CreditRating_is_valid_for_manager(this Person person)
{
if (person.IsManager) Assert.True(person.CreditRating >= 50);
}
}
/// <summary>
/// Traditional static class for helpers
/// </summary>
public static class PersonUniTestHelper
{
public static void Test_IncreaseCreditRating(Person person, int creditRating)
{
person.IncreaseCreditRating(creditRating);
if (creditRating >= 100) Assert.Equal(100 * 1000, person.CreditLimit);
else Assert.Equal(creditRating * 1000, person.CreditLimit);
}
public static void Test_CreditRating_is_valid_for_manager(Person person)
{
if (person.IsManager) Assert.True(person.CreditRating >= 50);
}
}
public class Person
{
public string FirstName { get; set; }
public int CreditLimit { get; private set; }
public int CreditRating { get; private set; }
public bool IsManager { get; set; }
/// <summary>
/// Simple action to set CreditLimit based on Rating.
/// </summary>
public void IncreaseCreditRating(int creditRating)
{
CreditRating = creditRating;
CreditLimit = creditRating >= 100 ? 100 * 1000 : creditRating * 1000;
}
}
}