我目前正在尝试重构一些单元测试,因为它们包含太多的硬编码数据。 类结构如下:
public class BaseClassValidator {
[Test]
public void TestAddress(){
Address a = GetAddress();
if (a != null){
// verify and validate here
Assert.AreEqual(..., ...);
}
}
[Test]
public void TestPhone(){
// almost the same as above, with GetPhone();
}
// ... other public methods here ...
protected Address GetAddress(){
return null;
}
protected Phone GetPhone(){
return null;
}
}
public class US: BaseClassValidator{
protected override Address GetAddress(){
Address address = new Address();
address.FirstName = "firstname";
// fill in the address data ...
return address;
}
// override GetPhone as well and other protected methods
}
以及许多用于相同目的的其他类 - 验证国家/地区地址是否有效。 每个子类都必须覆盖获取测试数据的方法,并且正如您可以想象的那样,这使得文件越来越大,输入数据在我看来可以被取出/设置不同。此外,这些子类中的一些定义了特定的测试成员来检查地址是有效还是无效,有几个检查,例如:
public class US: BaseClassValidator {
// override the method GetAddress, as explained above ...
// define a new test method here...
[Test]
public void TestValidator {
Address a = GetAddress();
a.State = "KS";
// validate the address
// and assert that we get an error because state is wrong
Address a = GetAddress();
a.street = "";
// validate and assert that we get an error because street is wrong
// and so on...
}
}
我想知道是否有更好的方法可以做到这一点,因为我们似乎部分使用基类来测试一些数据,但是对于更具体的东西我们正在使用子类 - 它可以有意义,但是那么我们似乎失去了使用上述模板模式的好处。我不喜欢的是数据的创建方式,因为使用不同的方法,例如使用数据驱动的测试,我们可以从文件中读取测试数据(例如,xml)。
有没有更好的方法在测试之间共享数据? 你是如何处理这种情况的?
答案 0 :(得分:0)
我目前正在开展类似的工作,并在我的项目中引入了Data
类。这只包含一堆静态数据。它是一个部分类,所以我可以稍微构建它。我有一个DataOrder.cs,DataOrderLine.cs等等。然后有公共属性,例如Orders
,我可以在测试中使用它来获取我的测试数据。
不要将所有数据都放在基类中,这将更难维护。
答案 1 :(得分:0)
我想知道是否有更好的方法来实现这一目标 我们部分使用基类来测试一些数据,但是 更具体的是我们正在使用子类 - 它可以制作 感觉,但似乎我们失去了使用模板的好处 像上面的模式。
人们倾向于使用Composition over inheritance这就是为什么使用子类不是单元测试的最佳解决方案。
您是否尝试过Object Mother或Test Data Builder模式?它们可以轻松地为您的测试构建数据。
有Test Data Builder用法的例子
var defaultAddres = new AddressBuilder().Build();
var addresWithState = new AddressBuilder().WithState("MyState").Build();
var addresWithStreet2 = new AddressBuilder().WithStreet2("street 2 value").Build();
及其简单实现
public class AddressBuilder
{
string state = "default STATE";
string street1 = "default street 1";
string street2 = "";
public Address Build()
{
return new Address
{
State = state,
Street1 = street1,
Street2 = street2
};
}
public AddressBuilder WithState(string value)
{
state = value;
return this;
}
public AddressBuilder WithStreet1(string value)
{
street1 = value;
return this;
}
public AddressBuilder WithStreet2(string value)
{
street2 = value;
return this;
}
}