Search code examples
c#dependency-injectionnunit

Dependency Injection in Nunit test classes via contructor or properties


I have IInterface with appropriate realization Realization which is registered in IUnityContainer (Unity framework):

public interface IInterface
{
    void Foo();
}

public class Realization : IInterface
{
    public void Foo() => Console.WriteLine("Test");
}

public class BaseFixture
{
    protected IUnityContainer Container { get; set; }

    [OneTimeSetUp]
    public void OneTimeSetUp()
    {
        Container = new UnityContainer()
            .RegisterType<IInterface, Realization>();
    }
}

I have Nunit TestFixture class in which I try to resolve the dependency in two ways:

Constructor:

[TestFixture]
public class MyTestClass1: BaseFixture
{
    public IInterface MyProp { get; set; }

    public MyTestClass1(IInterface instance)
    {
        MyProp = instance;
    }

    [Test]
    public void MyTest1()
    {
        MyProp.Foo();
    }
}

Property:

[TestFixture]
public class MyTestClass2 : BaseFixture
{
    [Dependency]
    public IInterface MyProp { get; set; }

    [Test]
    public void MyTest2()
    {
        MyProp.Foo();
    }
}

In the first case(constructor injection) I have the next exception on the runtime:

OneTimeSetUp: No suitable constructor was found

In the second case (property injection) the property is not initialized and has null value.

I would appreciate if anybody can advice the solution to use property or constructor injection. The only solution I've googled is: https://github.com/kalebpederson/nunit.dependencyinjection, but not sure that it is the best one.

Thanks.


Solution

  • Opinionated, but also fact-based interlude

    This answer keeps getting downvoted over its currently 8K views. Stop shooting the messenger.

    I understand why it may be tempting to have your entire DI setup just work and just write a unit test against a IoC-provided implementation of an interface, but it just goes against everything that proper unit testing stands for.

    1. First of all, a unit test tests that: one unit, being the System Under Test (SUT). You mock all of a SUT's dependencies.
    2. If you want to write your test against an interface, which implementation are you testing? You can break your tests by changing unrelated (DI setup) code or config. You tie a test to a specific implementation, not its interface.
    3. Which DI setup should run? Your main application's registration from your Program.cs with its (Web)HostBuilder, or your Startup.cs or whatever? Again, bad idea: do you really want your tests to use all of your main app's startup code? And what about its configuration? What if one of its dependencies actually accesses the filesystem, or a database, or a third-party mailing service, or...?
    4. If you want to test how multiple implementations interact, that's an integration test, not a unit test. And then still you want to use mocks to not talk to real databases, or at least ones with a different connection string and whatnot.
    5. If you insist, you could still use the library the OP links to. But I wouldn't.

    Original answer

    Why do you want to introduce dependency injection to your tests? That's not a common practice. There's no use injecting an interface implementation into your unit test.

    You don't want to test an interface, and you can't test an interface (unless you use default implementations, but that's another story).

    You want to test the concrete implementation of your interface, being Realization. So your test will look like this:

    [TestFixture]
    public class MyTestClass1
    {
        [Test]
        public void MyTest1()
        {
            // Arrange
            var classUnderTest = new Realization();
            
            // Act
            classUnderTest.Foo();
            
            // Assert
            // TODO: assertions
        }
    }
    

    Everything you're trying to do in the code in your question has exactly the same purpose and achieves exactly the same, using a DI container. That's just unit testing with extra steps.

    If you are really sure you want this, you can use the library you link to. This instructs the NUnit framework to call your dependency injection framework to provide injection for your tests.

    But again, don't do that. You want to test Realization, then test Realization. Don't put yourself through extra, unnecessary hoops to get an interface into your test.