简体   繁体   中英

How to update the properties of already registered class in Autofac container in Nunit Framework

I use a dependency injection framework AutoFac in NUnit as described here

The classes are registered as SingleInstance scope.

one of the classes depends on Setting class, as given below:

    class Product
    {
       public (Setting setting, Dep1 dependency) {....   }
       ....
     }

I want to update the properties of one of the classes "Setting" per test case.

 [Test]
 public void Test()
 {

  //Arrange
  var setting = Resolve<Setting>
  Setting.Id = value
  // product depend on two dependency injected via constructor
  var product = Resolve<Product> ; 

  //the problem is: the new values of setting class are not reflected in 
   //Product, and the Product still use the default values provided by the container

    ......        

  }

The problem is the updated value is not reflected in the container and unit test fail and the Product class still use the default values

I tried to use this solution , but it can't help.The Documentation of AutoFac don't provide guidelines of using in NUnit or test suite.

The question: How can I update the values of the class setting and the new values are auto injected in the constructor of product class in NUnit ?

The Short Answer

You don't.

The Long Answer

Each application should have its own Composition Root . Since a test project is a separate application from the class under test, you would never share a production configuration with a test configuration .

When unit testing, you typically don't deal with more than half a dozen or so dependencies at a time. It would be impractical to setup a DI container for this purpose. Instead, you should new up the class under test and mock everything else except for DTO and Model objects.

[Test]
public void Test()
{
    var setting = new Setting { Value1 = "x", Value2 = "y" };
    var dep1 = new Mock<Dep1>();
    // setup Moq conditions on dep1

    var product = new Product(setting, dep1);

    // Execute method on product and assert
}

When integration testing, it is also better to use pure DI than to setup a DI container just for the purpose of testing. However, if you do use a DI container, it should have its own configuration separate from the application that is being tested. Even if this weren't considered a bad practice, there will be dependencies that need to be mocked that warrant this anyway. You are not testing the DI container configuration, you are testing the components of your application , so there is no need to make them one and the same.

NOTE: It is strongly advised to use abstractions rather than concrete types as constructor parameters. The usual route is to use interfaces (although I would argue that "settings" might not need to be), but abstract classes will also work.

Instead of trying to update the properties of your Settings class, you can create an interface to represent your settings, like

public interface ISettings
{
    int Value { get; }
}

Inject that interface, not a concrete class, into your Product class. Your concrete implementation might read from a configuration file, or you could have an implementation with hard-coded values - whatever you need.

But now that your class depends on that interface, for testing you have a number of options for mocking it.

You could use a test double, like:

public class SettingsDouble : ISettings
{
    public int Value { get; set; }
}

Or you could use Moq .

var settingsMock = new Mock<ISettings>();
settingsMock.Setup(x => x.Value).Returns(1);

A side effect is that your ISettings interface and implementations can have read-only properties. Chances are that you don't want classes setting those properties at runtime and affecting other classes' settings, but you made it writable for the purpose of unit testing. Now you don't have to do that.

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