Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock IOptionsSnapshot instance for testing

I have class AbClass that get with asp.net core built-in DI instance of IOptionsSnapshot<AbOptions> (dynamic configuration). now I want to test this class.

I'm trying to instantiate AbClass class in test class, but I have no idea how can I instantiate an instance of IOptionsSnapshot<AbOptions> to inject into the constructor of AbClass.

I tried use Mock<IOptionsSnapshot<AbOptions>>.Object, but I need to set some values to this instance, since in AbClass the code is using this values (var x = _options.cc.D1).

so I have a code like

var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(new Dictionary<string, string>
{
    ["Ab:cc:D1"] = "https://",
    ["Ab:cc:D2"] = "123145854170887"
});
var config = builder.Build();
var options = new AbOptions();
config.GetSection("Ab").Bind(options);

but I dont know how to link this Options and the IOptionsSnapshot mock.

AbClass:

public class AbClass {
    private readonly AbOptions _options;

    public AbClass(IOptionsSnapshot<AbOptions> options) {
        _options = options.Value;    
    }
    private void x(){var t = _options.cc.D1}
}

my test instantiate this class:

var service = new AbClass(new Mock???)

and need to test a method in AbClass that call x(), but it throw ArgumentNullException when it on _options.cc.D1

like image 289
arielorvits Avatar asked Dec 12 '16 23:12

arielorvits


2 Answers

You should be able to mock up the interface and create an instance of the options class for the test. As I am unaware of the nested classes for the options class I am making a broad assumption.

Documentation: IOptionsSnapshot

//Arrange
//Instantiate options and nested classes
//making assumptions here about nested types
var options = new AbOptions(){
    cc = new cc {
        D1 = "https://",
        D2 = "123145854170887"
    }
};
var mock = new Mock<IOptionsSnapshot<AbOptions>>();
mock.Setup(m => m.Value).Returns(options);

var service = new AbClass(mock.Object);

Access to the nested values should now return proper values instead of NRE

like image 112
Nkosi Avatar answered Oct 17 '22 23:10

Nkosi


A generic way:

    public static IOptionsSnapshot<T> CreateIOptionSnapshotMock<T>(T value) where T : class, new()
    {
        var mock = new Mock<IOptionsSnapshot<T>>();
        mock.Setup(m => m.Value).Returns(value);
        return mock.Object;
    }

usage:

var mock = CreateIOptionSnapshotMock(new AbOptions(){
    cc = new cc {
        D1 = "https://",
        D2 = "123145854170887"
    }
});
like image 40
Bastiflew Avatar answered Oct 18 '22 01:10

Bastiflew