1

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.

  • 1
    Please show a relevant code block, not just single lines. Are you giving your unit test a constructor, and do you want IServiceDal injected for testing? Why not instantiate ServiceDal in your test, if that is the class you want to test? – CodeCaster Nov 26 '21 at 12:38
  • The point is, see also the warning in the readme of the repo you link to, that unit tests should not need dependency injection. Where should it get the DI container from anyway? Call your application's startup code? Custom DI per test, test project or category/suite? Reconsider your approach or explain why you think you need this (preferably with some actual test code). – CodeCaster Nov 26 '21 at 12:46
  • 1
    +1 on both comments from @CodeCaster. In addition, please explain what you are testing. If you are testing ServiceDa1, then NUnit has an approach you may use. If you are testing something else and ServiceDa1 is merely incidental, it's another matter. – Charlie Nov 26 '21 at 14:47
  • @CodeCaster Thanks for the answers. I've updated the code snippets appropriatly. This is my self-education activities, I want just to figure out the possibility of using constructor and property injection in nunit test fixture classes. – Vitali Sonchyk Nov 29 '21 at 08:37

1 Answers1

-4

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.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 1
    Thanks for the answer. That can bee not only unit tests,but integration tests UI whatever which can be tested with nUnit. And the injected realization can be not only the realization of class we want to test. – Vitali Sonchyk Nov 29 '21 at 09:25
  • None of that introduces the need for DI in your tests. If you have multiple implementations of the same interface and you want to test them all the same way, use data-driven tests or repeated test runs or whatever. Dependency injection simply is not a good idea for unit tests. – CodeCaster Nov 29 '21 at 09:29
  • If you want help getting your actual scenario to work, then show enough context about your scenario. I don't know what exactly you're trying to do. If you're bound on DI, then use that library you link to. – CodeCaster Nov 29 '21 at 09:30
  • 2
    I agree you shouldn't be testing interfaces. But if your implementation has a dependency on, say, an IOptions interface, wouldn't it make sense to let DI handle the injection? Sure you could create the configuration model yourself, but that is arguably outside of the scope of the test. – AsPas May 19 '22 at 08:28
  • @AsPas you'll be testing whether your code responds to specific options. So see https://stackoverflow.com/questions/40876507/net-core-unit-testing-mock-ioptionst#40898882. The scope of my answer here is using dependency injection to inject stuff into your tests, which usually is a bad idea. – CodeCaster May 19 '22 at 10:21
  • I agree with injecting services from your sut into your tests being a bad idea however I disagree with rejecting DI altogether in tests. Especially in integration tests injecting things like a testcontainer can be a very good and clean way of setting up such a test. These setups can be more complex and can really benefit from DI and the lifetime handling of containers so you can keep that complexity out of your tests. – Barsonax Jul 15 '23 at 08:34
  • @Barsonax I get that, but what kind of answer were your expecting to this question? How to set up a "test container"? – CodeCaster Jul 16 '23 at 07:16