差异测试可以作为单元测试接受,尤其是当您使用单元测试之间共享的测试数据时。
如果您不知道 SUT 中有多少项目,您可以使用以下方法:
int itemsBeforeTest = SUT.Items.Count;
SUT.AddItem();
Assert.AreEqual(itemsBeforeTest + 1, SUT.Items.Count);
如果一个单元测试需要大量数据,以至于需要从一个大的 XML 文件中读取,那么它就不是真正的单元测试。单元测试应该完全隔离地测试一个类并模拟所有依赖项。
使用Builder pattern 之类的模式也有助于为您的单元测试创建测试数据。将测试数据放在单独的文件中的最大问题是很难理解测试的确切作用。如果您在单元测试的安排部分中创建测试数据,那么您会立即清楚什么对您的测试很重要。
例如,假设您有以下排列代码来测试发票价格是否正确:
Address billingAddress = new Address("Stationsweg 9F",
"Groningen", "Nederland", "9726AE"); shippingAddress = new Address("Aweg 1",
"Groningen", "Nederland", "9726AB");
Customer customer = new Customer(99, "Piet", "Klaassens",
30,
billingAddress,
shippingAddress);
Product product = new Product(88, "Tafel", 19.99);
Invoice invoice = new Invoice(customer);
使用Builder时可以改为如下
Invoice invoice = Builder<Invoice>.CreateNew()
.With(i => i.Product = Builder<Product>.CreateNew()
.With(p => p.Price = 19.99)
.Build())
.Build();
使用 Builder 时,更容易看出什么是重要的,并且您的代码也更易于维护。
重构代码以提高可测试性是一个广泛的话题。归结为思考“我将如何测试这段代码?”在你写代码的时候。
举个例子:
public class AlarmClock
{
public AlarmClock()
{
SatelliteSyncService = new SatelliteSyncService();
HardwareClient = new HardwareClient();
}
}
这很难测试。在测试闹钟时,您需要确保 SatteliteSyncService 和 HardwareClient 都正常工作。
对构造函数的这种更改使测试变得更加容易:
public AlarmClock(IHardwareClient hardwareClient, ISatelliteSyncService satelliteSyncService)
{
SatelliteSyncService = satelliteSyncService;
HardwareClient = hardwareClient;
}
Dependency Injection 等技术有助于重构您的代码,使其更具可测试性。还要注意静态值,例如 DateTime.Now 或使用 Singleton,因为它们很难测试。
关于编写可测试代码的非常好的介绍可以在here 找到。