c# - 每个接口或每个实现创建一个完整的测试套件
问题描述
我想知道如果每个接口有多个实现,编写测试的最佳实践是什么。
我是否必须为每个实现复制每个测试,或者我可以创建一个包含有关接口的所有测试的抽象类,然后为每个实现创建一个简单的测试类来扩展我的抽象测试类?
我正在关注 Osherove 写的“单元测试的艺术”,他总是重复说我们必须保持测试和测试套件尽可能简单,所以我不知道添加抽象类是否会增加复杂性阅读其他开发人员的测试。
以下哪个示例被普遍接受且更具可读性?
示例代码:
public interface IMyInterface()
{
public string MyMethod(string input);
}
public class MyClassA : IMyInterface
{
public string MyMethod(string input)
{
return input;
}
}
public class MyClassB : IMyInterface
{
public string MyMethod(string input)
{
return "hello from MyClassB";
}
}
public class MyClassC : IMyInterface
{
public string MyMethod(string input)
{
throw new NotImplementedException();
}
}
测试套件 1:
[TestFixture]
public class MyClassATest {
[Test]
public void MyMethod_WhenCalled_ReturnsANotNullString()
{
//arrange
MyClassA sut = new MyClassA();
//act
string result = sut.MyMethod("hi");
//assert
Assert.IsNotNull(result);
}
}
[TestFixture]
public MyClassBTest {
[Test]
public void MyMethod_WhenCalled_ReturnsANotNullString()
{
//arrange
MyClassA sut = new MyClassB();
//act
string result = sut.MyMethod("hi");
//assert
Assert.IsNotNull(result);
}
}
[TestFixture]
public MyClassCTest {
[Test]
public void MyMethod_WhenCalled_ReturnsANotNullString()
{
//arrange
MyClassA sut = new MyClassC();
//act
string result = sut.MyMethod("hi");
//assert
Assert.IsNotNull(result);
}
}
测试套件 2:
[TestFixture]
public abstract class IMyInterfaceTest<TImplementation> where TImplementation : IMyInterface {
[Test]
public void MyMethod_WhenCalled_ReturnsANotNullString()
{
//arrange
TImplementation sut = new MyClassC();
//act
string result = sut.MyMethod("hi");
//assert
Assert.IsNotNull(result);
}
}
[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassA> {}
[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassB> {}
[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassC> {}
解决方案
为什么不使用 TestCaseSource ( https://github.com/nunit/docs/wiki/TestCaseData ) 尝试这种方法。好处是你有一个测试而不是许多重复测试做同样的事情。
[TestCaseSource(typeof(MyDataClass), "TestCases")]
public void MyMethod_WhenCalled_ReturnsANotNullString(IMyInterface sut, string value)
{
//arrange
//act
string result = sut.MyMethod(value);
//assert
Assert.IsNotNull(result);
}
public class MyDataClass
{
public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new MyClassA(), "hi");
yield return new TestCaseData(new MyClassB(), "test");
yield return new TestCaseData(new MyClassC(), "another");
}
}
}
推荐阅读
- sharepoint - SharePoint 2016 FBA 本地 DUO .NET WebSDK
- c++ - 如何以独立于平台的方式从 C++ 目录中读取文件?
- sql - 列之间的 SQL 操作
- r - Different results for SVM using Caret in R when classProbs=TRUE
- python - 使用 np.where 在 matplotlib 中按类别着色
- python - 如何使用 Pytorch 和/或 Numpy 在多维矩阵数组中有效地查找最大值的索引
- postgresql - tokio-postgres 和数据库查询
- excel - 将变量应用于循环错误-“For Each 只能遍历集合对象或数组”
- mysql - Heroku 构建失败的 node.js
- html - 下拉列表值更改后如何设置重新聚焦?