我已经检查了这个.. similar question但是我不相信答案......
我目前有一个只由一个类实现的接口,但这迟早会发生变化。我目前对接口进行了测试,开头的所有测试都以:
开头IFoo foo = GetConcreteFoo()
其中GetConcreteFoo类似于
IFoo GetConcreteFoo()
{
return new ConcreteFooA();
}
但是,当我获得更多Foo的实现时,是否有办法让所有测试运行在所有不同具体foos的列表中?
我想如果没办法,至少我可以将测试复制/粘贴到一个新文件中,并使用具体类的名称,并更改GetConcreteFoo的返回对象... (并将原始文件从(IFooTests更改为IConcreteFooATests)。
我不认为这种方法特别糟糕..但它不太优雅/聪明,因为它会针对所有具体实现运行相同的测试(文件)。
有没有办法让它做到这一点?
(我正在使用MSTests)
谢谢!
答案 0 :(得分:3)
不确定MSTest,但我相信您可以使用parameterised tests在NUnit中执行此操作,例如:使用实现类进行参数化并使用Activator.CreateInstance实例化它。
然而,更深层次的问题是,你想要吗?您没有说出您的界面是什么样的,但拥有界面的通常原因是允许不同的实现。例如,如果您有一个带有Area属性的IShape接口,那么Circle,Square和RorschachBlot将以不同的方式实现。什么可以测试IShape.Area属性可靠地断言?因此,一般来说,您可以实际测试类和(具体)方法。
当然,如果你的界面意味着界面规范之外的语义保证(例如,Area总是大于0),那么你可以测试你所知道的所有实现。 (对于您在创建测试时不了解的实现,您必须依赖于带外通信这些额外需求,例如通过文档和信任实现者来遵守它们。当代码合同发布时,您将能够强制执行通过合同类更可靠地满足这些要求。)
答案 1 :(得分:2)
简短回答,是的,你可以。更长的答案是它取决于很多因素,如何在你的测试套件中。
基本上你可以这样做:
public void GenericIFooTest(IFoo testFoo) {
// each of your tests against foo here...
Assert.IsTrue(testFoo.DoesItsThing());
}
然后您可以手动生成测试:
public void TestConcreteAFoo() {
IFoo aFoo = new ConcreteAFoo(param1, param2, param3);
GenericIFooTest(aFoo);
}
public void TestConcreteBFoo() {
IFoo bFoo = new ConcreteBFoo();
GenericIFooTest(bFoo);
}
或者你可以使用反射来做到这一点。这假设你知道如何动态地实例化每个foo,如果它有一个最好的默认构造函数:
public void TestAllFoos() {
foreach(string assembly in Directory.GetFiles(assemblyPath, "*.dll", SearchOptions.All) {
Assembly currentAssembly = Assembly.LoadAssembly(assembly);
foreach(Type internalTypes in currentAssembly.GetTypes()) {
if (internalTypes.IsAssignableFrom(IFoo) && !(internalTypes is IFoo)) {
IFoo fooType = AppActivator.CreateInstance(internalTypes);
GenericIFooTest(fooType);
}
}
}
}
最后一部分是从我上周写的一些代码的记忆来做同样的事情,它有点粗糙,但应该让你开始。你当然可以使用LINQ来简化它,我只是不知道我头脑中的语法。