我有一些ISome接口。有4个类,比如MyClass1:ISome,MyClass2:ISome等。如何用NUnit从这个接口测试一些方法,但只对所有类进行一次单元测试?
发布于 2011-11-06 02:05:23
4个类意味着给定方法的4个不同实现。因此,您应该有4个单元测试。尝试编写单个单元测试是错误的。
发布于 2011-11-06 05:02:10
如何使用NUnit从这个接口测试一些方法,但只对所有类进行一次单元测试?
你写这篇文章的方式,人们可以将其解释为“单个单元测试,句号”。这当然是一个非常糟糕的想法。
理想情况下,您希望每个测试用例只有一个断言,并且确实必须在代码中断言所有不同的逻辑片段。每个类都有多个逻辑,接口的每个实现都是一个明显不同的逻辑(即使它具有相同的接口,即使您复制并粘贴了代码)。
因此,您面临一个选择:您需要多个单元测试。
代码复制
为了避免重复单元测试代码,您可以尝试NUnit的参数化单元测试功能。
有了它,您可以将实际编写的单元测试方法的数量乘以提供给这些测试的实例的数量。这些实例可以是不同的实现。
在NUnit中有很多方法可以参数化您的测试。请参阅本文:
我个人更喜欢TestCaseSource属性:
NUnit测试运行器仍将显示您编写的每个单元测试方法,但会将数据数组中的每个项目显示为子测试。
这些方法很难学习如何使用,因为您必须将测试分解到数据驱动的模型中。
如何在实现上参数化
如果您的接口中给定方法的实现只是输出不同的数据,那么您可能就走运了。例如,如果你在一个实现中测试乘法,在另一个方法中测试加法,你的矩阵可能是这样的:
Impl Input1 Input2 Result
Multiply 0 7 0
Multiply 3 6 18
Add 0 0 0
Add 5 6 11您将返回一个包含此矩阵中每一行的数组,包括您正在运行的接口的哪个实现,将这些数组提供给包含测试的一般流程的单个单元测试方法,然后调用它。
下面是一些实现这些操作的示例代码:
// This interface takes two ints, returns one int
public interface IBinaryOperation
{
int Execute(int x, int y);
string Name { get; }
}
public class Add : IBinaryOperation
{
public int Execute(int x, int y) { return x + y; }
public string Name { get { return "Add"; } }
}
public class Multiply : IBinaryOperation
{
public int Execute(int x, int y) { return x * y; }
public string Name { get { return "Multiply"; } }
}下面是一个测试fixture实现的示例:
[Test, TestCaseSource("OperationTestCases")]
public void ExecuteReturnsCorrectResult(
IBinaryOperation operation,
int inputX, int inputY,
int expectedResult
)
{
int actualResult = operation.Execute(inputX, inputY);
Assert.That(actualResult, Is.EqualTo(expectedResult),
"Expected operation: '{0}', with '{1}' and '{2}' to return '{3}'"
, operation.Name
, inputX
, inputY
, expectedResult
);
}
static object[] OperationTestCases =
{
new object[] { new Multiply(), 0, 7, 0 },
new object[] { new Multiply(), 3, 6, 18 },
new object[] { new Add(), 0, 0, 0 },
new object[] { new Add(), 5, 6, 11 },
};

更复杂的示例
如果您的实现彼此之间的差异比这更大,或者您不能创建一个简单的输入/输出矩阵,那么您将面临一段艰难的时期。
一种选择是将委托加入到测试用例中。但这就像听起来那样复杂,不清楚,也很难维护。在这种情况下,您最好编写单独的单元测试方法。
发布于 2011-11-06 02:08:50
Darin Dimitrov通常是正确的,但为了方便起见,您可以为所有实现实现一个抽象测试用例。有一个抽象方法,比如
protected abstract ISome createInstance();在从抽象测试类继承的测试用例中覆盖它也是可行的。
https://stackoverflow.com/questions/8022165
复制相似问题