'Moq - mocking inherited/segregated interfaces
I've got a large QueryModel class that overall looks like this:
public class QueryModel: IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
public interface IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
The IQueryModel is passed around when our API is processing a request. In our (very large) codebase, most code is effectful, so the model is both read and mutated freely.
I'm slowly separating pure and effectful code (in relation to this model) by introducing an immutable interface, to be passed to pure code only, like this:
// unchanged
public class QueryModel: IQueryModel
{
public int Property1 { get; set; }
... ~100 more fields like this
}
public interface IQueryModel : IQueryModelImmutable
{
public int Property1 { get; set; } // still implements both getters and setters
... ~100 more fields like this
}
public interface IQueryModelImmutable
{
public int Property1 { get; } // only has getters
... ~100 more fields like this
}
But now in each unit test, when mocking IQueryModel, I need to duplicate all set-ups like this:
Mock<IQueryModel> _queryModelMock = new(); // existing setup
_queryModelMock.Setup(m => m.Property1).Returns(100); // existing setup
_queryModelMock.As<IQueryModelImmutable>.Setup(m => m.Property1).Returns(100); // new setup
The production code is working fine, as the interface properties are simply inherited and resolved in the class, however Moq seems to require that the exact interface (and not its descendant) was mocked.
Is there any way to simplify these mock definitions, by e.g. enabling mock inheritance in some way?
EDIT: to explain why I need to use/mock both interfaces, here's a relevant piece of code under test:
// 1k LoC
public async Task LongStatefulMethod(IQueryModel model)
{
...
CallAnEffecfulMethod(model); // model mutated
...
// ComputeScorePure accepts the base interface - IQueryModelImmutable - as an argument
var computedScore = ComputeScorePure(model); // model not mutated
...
CallAnotherEffectfulMethod(model); // model mutated
...
}
Solution 1:[1]
You can workaround using Mock.Of<> or Mock.SetupAllProperties and setting the property manually:
// Mock<IQueryModel> mock = new ();
// mock.SetupAllProperties();
// var inherited = mock.Object;
var inherited = Mock.Of<IQueryModel>();
inherited.Property1 = 100;
IQueryModelImmutable @base = inherited;
Assert.AreEqual(100, inherited.Property1);
Assert.AreEqual(100, @base.Property1);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Guru Stron |
