简体   繁体   English

具有无参数构造函数的NUnit TestFixture

[英]NUnit TestFixture with no-arg constructors

How do you get around the scenario where the TestFixture you are trying to define needs to reference types that do not have a no-arg constructor? 在要定义的TestFixture需要引用没有no-arg构造函数的类型的情况下,如何解决?

I'm trying to test an interface that has multiple implementations. 我正在尝试测试具有多个实现的接口。 From the NUnit documentation it showed how this could be setup with generics like this (where I can define multiple implementation types): 从NUnit文档中,它展示了如何使用这样的泛型(在这里我可以定义多种实现类型)进行设置:

[TestFixture(typeof(Impl1MyInterface))]
[TestFixture(typeof(Impl2MyInterface))]
[TestFixture(typeof(Impl3MyInterface))]
public class TesterOfIMyInterface<T> where T : IMyInterface, new() {

    public IMyInterface _impl;

    [SetUp]
    public void CreateIMyInterfaceImpl() {
        _impl = new T();
    }
}

The problem arises because Impl1MyInterface, Impl2MyInterface, etc do not have no-arg constructors so when NUnit tries to discover the available test cases I get this error (and the tests do not show up in VS): 出现问题是因为Impl1MyInterface,Impl2MyInterface等没有no-arg构造函数,因此当NUnit尝试发现可用的测试用例时,我会收到此错误(并且测试未在VS中显示):

Exception System.ArgumentException, Exception thrown discovering tests in XYZ.dll 异常System.ArgumentException,在XYZ.dll中发现测试时引发异常

Is there a way to work around this? 有办法解决这个问题吗? It doesn't make sense to define no-arg constructors because my code needs those values to work. 定义无参数构造函数是没有意义的,因为我的代码需要这些值才能起作用。

Instead of using new T() to instantiate your objects, you could use a dependency injection container to instantiate them for you. 代替使用new T()实例化对象,可以使用dependency injection container为您实例化它们。 Here's an example using Microsoft's Unity: 这是使用Microsoft Unity的示例:

[SetUp]
public void CreateIMyInterfaceImpl() {
    var container = new UnityContainer();

    // Register the Types that implement the interfaces needed by
    // the Type we're testing.
    // Ideally for Unit Tests these should be Test Doubles.
    container.RegisterType<IDependencyOne, DependencyOneStub>();
    container.RegisterType<IDependencyTwo, DependencyTwoMock>();

    // Have Unity create an instance of T for us, using all
    // the required dependencies we just registered
    _impl = container.Resolve<T>();   
}

As @Steve Lillis has said in his answer, you need to stop using new T() . 就像@Steve Lillis在回答中所说的那样,您需要停止使用new T() When you do this, you don't need to use the new constraint on your generic. 执行此操作时,无需在泛型上使用new约束。 One option would be to use an IOC container, like Castle Windsor / Unity as Steve suggested to resolve the dependencies in your Setup. 一种选择是使用IOC容器,如史蒂夫建议的解决城堡中的依赖关系一样,使用Castle Windsor / Unity。

You haven't said what parameters your implementation's constructors take, but if they're all the same, then an alternate would be to use Activator.CreateInstance instead. 您没有说实现的构造函数采用什么参数,但是如果它们都相同,则可以选择使用Activator.CreateInstance代替。 So, if your constructors all took an integer and a string, your code would look like this: 因此,如果所有构造函数都使用整数和字符串,则代码将如下所示:

[TestFixture(typeof(Impl1MyInterface))]
[TestFixture(typeof(Impl2MyInterface))]
[TestFixture(typeof(Impl3MyInterface))]
public class TesterOfIMyInterface<T> where T : IMyInterface {

    public IMyInterface _impl;

    [SetUp]
    public void CreateIMyInterfaceImpl() {
        int someInt1 = 5;
        string someString = "some value";
        _impl = (T)Activator.CreateInstance(typeof(T), new object[] { someInt1, someString });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM