Reputation: 119
My C# classes are generally structured this way:
public class MyDummyService
{
private readonly MyConfigClass _config;
public MyDummyService(IOptions<MyConfigClass> options)
{
_config = options.Value;
}
public string DoSomethingWithTheNumber()
{
if (_config.SomeValue % 2 == 0)
return "foo";
return "bar";
}
}
public class MyConfigClass
{
public int SomeValue{get; set;}
public string SomeName {get; set;}
}
Clearly, IOptions<MyConfigClass>
is used to map configurations from the appSettings.json file.
Then, I can test such classes like this:
class MyDummyServiceTests
{
protected AutoFixture.Fixture _fixture;
protected MyDummyService _sut;
protected MyConfigClass _simpleConfig;
protected Mock<IOptions<MyConfigClass>> _mockConfig;
public MyDummyServiceTests()
{
_fixture = new AutoFixture.Fixture();
_mockConfig = new Mock<IOptions<MyConfigClass>>();
_simpleConfig = _fixture.Build<MyConfigClass>()
.With(i => i.SomeValue, 4)
.With(i => i.SomeName, "Pippo")
.Create();
}
[SetUp]
public void Setup()
{
_mockConfig.SetupGet(m => m.Value).Returns(_simpleConfig);
_sut = new MyDummyService(_mockConfig.Object);
}
[TearDown]
public void TearDown()
{
_mockConfig.Reset();
}
public class DoSomethingWithTheNumber : MyDummyServiceTests
{
[Test]
public void Should_ReturnFoo_WhenNumberIsEven()
{
_simpleConfig = _fixture.Build<MyConfigClass>()
.With(_ => _.SomeValue, 10)
.Create();
var s = _sut.DoSomethingWithTheNumber();
Assert.AreEqual("foo", s);
}
[Test]
public void Should_ReturnBar_WhenNumberIsOdd()
{
_simpleConfig = _fixture.Build<MyConfigClass>()
.With(_ => _.SomeValue, 69)
.Create();
var s = _sut.DoSomethingWithTheNumber();
Assert.AreEqual("bar", s);
}
}
}
Yes, I know, I should use [TestCase] - you got the point
Now, when I set up tests for such classes, and I want to test a specific behavior that depends on the MyConfigClass.SomeValue
value, I don't want to re-initialize everything. I can clearly just add _mockConfig.SetupGet(m => m.Value).Returns(_simpleConfig);
or _sut = new MyDummyService( Options.Create(_simpleConfig));
but I want to keep my tests as small as possible, and only set the configuration value I need.
If I run the tests as such, DoSomethingWithTheNumber()
does not see MyConfigClass.SomeValue
with the correct value, because it is initialized and assigned to _config
during StartUp phase, so before I set the correct value in my tests.
How can I improve my approach and set only the values necessary to have the specific test pass?
Note: I do not expect my configurations to change at runtime. Therefore, I can use IOptions<T>
, IOptionsMonitor<T>
, or IOptionsSnapshot<T>
- even if they are different meanings, as explained here.
Upvotes: 2
Views: 369
Reputation: 132
You just need to reinitialize _simpleConfig but do not change the reference to:
[Test]
public void Should_ReturnFoo_WhenNumberIsEven()
{
_simpleConfig.SomeValue = 10;
var s = _sut.DoSomethingWithTheNumber();
Assert.AreEqual("foo", s);
}
Upvotes: 0