简体   繁体   中英

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?

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):

[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):

Exception System.ArgumentException, Exception thrown discovering tests in 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. Here's an example using Microsoft's 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() . When you do this, you don't need to use the new constraint on your generic. One option would be to use an IOC container, like Castle Windsor / Unity as Steve suggested to resolve the dependencies in your Setup.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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