有没有一种方法可以为接口编写测试,然后针对实现该测试的所有类进行测试?

发布于 2024-08-15 02:48:35 字数 693 浏览 1 评论 0原文

我已经检查过这个.. 类似的问题 但我对答案并不确信......

我目前有一个仅由一个类实现的接口,但这迟早会改变。我目前对接口进行了一个测试,并且一开始的所有测试都从以下内容开始:

IFoo foo = GetConcreteFoo()

其中 GetConcreteFoo 类似于

IFoo GetConcreteFoo()
{
   return new ConcreteFooA();
}

但是,当我获得更多 Foo 的实现时,是否有一种方法可以使所有测试针对所有的列表运行不同的具体食物?

我想,如果没有办法,至少我可以将测试复制/粘贴到一个新文件中,并使用具体类的名称,并更改 GetConcreteFoo 的返回对象... (并将原始文件从 (IFooTests 更改为 IConcreteFooATests)。

我不认为这种方法特别糟糕..但它不太优雅/聪明,因为它将针对所有具体实现运行相同的测试(文件)。

有吗有办法让它做到这一点吗?

(我正在使用 MSTests )

谢谢!

I've already checked this.. similar question but I am not convinced about the answers...

I currently have an interface that is only being implemented by one class, but that is going to change sooner or later. I currently have a test against the interface, and all tests at the beginning start with:

IFoo foo = GetConcreteFoo()

where GetConcreteFoo is something like

IFoo GetConcreteFoo()
{
   return new ConcreteFooA();
}

however, when I get more implementations of Foo, could there be a way to make all the test run against a list of all the different concrete foos?

Im thinking that if there is no way, at least I can copy/paste the test into a new file, with the name of the concreteclass, and change the return object of the GetConcreteFoo...
(and changing the original file from (IFooTests to IConcreteFooATests).

I dont think this method is particularly bad.. but its not too elegant/clever, as it would be to run the same test (file) against all concrete implementations.

Is there a way to make it do that?

(Im using MSTests )

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

归属感 2024-08-22 02:48:35

不确定 MSTest,但我相信您可以在 NUnit 中使用 参数化测试< /a>,例如使用实现类进行参数化并使用 Activator.CreateInstance 来实例化它。

然而,更深层次的问题是,你愿意吗?您没有说明您的接口是什么样子,但拥有接口的通常原因是允许不同的实现。例如,如果您有一个带有 Area 属性的 IShape 接口,则 Circle、Square 和 RorschachBlot 将以不同的方式实现该接口。 IShape.Area 属性的测试可以可靠地断言什么?因此,一般来说,您实际上只能测试类和(具体)方法。

当然,如果您的接口旨在暗示接口规范之外的语义保证(例如,面积始终大于 0),那么您可以针对您了解的所有实现进行测试。 (对于创建测试时您不知道的实现,您必须依靠带外通信这些附加要求,例如通过文档,并信任实现者遵守它们。当发布代码合同时,您将能够强加通过合约类更可靠地满足此类要求。)

Not sure about MSTest, but I believe you could do this in NUnit using parameterised tests, e.g. parameterising with the implementation class and using Activator.CreateInstance to instantiate it.

However, the deeper question is, would you want to? You don't say what your interface looks like, but the usual reason for having an interface is to permit different implementations. For example, if you have an IShape interface with an Area property, that will be implemented differently by Circle, Square and RorschachBlot. What could a test for the IShape.Area property reliably assert? In general, therefore, you can realistically test only classes and (concrete) methods.

Of course, if your interface is meant to imply semantic guarantees outside the interface spec (e.g. Area is always greater than 0) then you could test that for all implementations you know about. (For implementations you don't know about when you create the test, you must rely on communicating these additional requirements out of band, e.g. through documentation, and trusting implementors to obey them. When Code Contracts are released, you will be able to impose such requirements more reliably via contract classes.)

Bonjour°[大白 2024-08-22 02:48:35

简短的回答,是的,可以。更长的答案是,这将取决于很多因素,以及它在测试套件中的表现。

基本上你可以做这样的事情:

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 来简化它,我只是不知道语法。

Short answer, yes you can. Longer answer is it will depend on a lot of factors as to how it goes in your test suite.

Basically you can do something like this:

public void GenericIFooTest(IFoo testFoo) {
   // each of your tests against foo here...
   Assert.IsTrue(testFoo.DoesItsThing());
}

You could then generate your tests manually:

public void TestConcreteAFoo() {
   IFoo aFoo = new ConcreteAFoo(param1, param2, param3);

   GenericIFooTest(aFoo);
}
public void TestConcreteBFoo() {
   IFoo bFoo = new ConcreteBFoo();

   GenericIFooTest(bFoo);
}

Or you could use reflection to do it. This assumes you know how to instantiate each foo dynamically, if it has a default constructor that would be best:

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);
         }
      }
   }
}

The last part is from memory of some code I was writing last week to do the same thing, its a little rough but should get you started. You could of course use LINQ to simplify it, I just dont know the syntax off the top of my head.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文