I have a class that has an expression-bodied member:
public MyState
{
public List<Thing> Things { get; set; }
public double SomeValue => Things.sum(thing => thing.Value);
public double MyProperty { get; set; }
}
I need to write a unit test for a method Apply()
whose signature looks like this:
public OtherClass
{
public override MyList Apply(MyState state) {
state.MyProperty = state.SomeValue;
return null;
}
}
public void Test()
{
var mock = new Mock<MyState>();
mock.SetupGet(mock => mock.SomeValue).Returns(100.0);
var otherClass = new OtherClass();
otherClass.Apply(mock.Object);
...
}
This resulted in an error stating that SomeValue
is a non-overridable member.
I then implemented an interface IMyState
like so:
public interface IMyState
{
double SomeValue { get; set; }
double MyProperty { get; set; }
}
and modified my test to implement that interface for the mock. This resulted in an error calling the Apply()
method that I want to test, because Apply
takes an instance of MyState
rather than IMyState
:
public void Test()
{
var mock = new Mock<MyState>().As<IMyState>(); // implement interface here
mock.SetupGet(mock => mock.SomeValue).Returns(100.0);
var otherClass = new OtherClass();
otherClass.Apply(mock.Object); // mock.Object is of class IMyState
...
}
I'm guessing this is because MyState
does not actually implement IMyState
. Is there some way I can mock this property to return a specified value without changing MyState
to implement IMyState
(or declare SomeValue
as virtual
, which I've seen in other StackOverflow posts)? I'd prefer not to make changes to the existing code solely for the purpose of testing.
I tried casting the mock back to MyState
before passing it to Apply()
, but SomeValue
then returned 0
rather than 100.0
as I set the mock up to return:
public void Test()
{
var mock = new Mock<MyState>().As<IMyState>();
mock.SetupGet(mock => mock.SomeValue).Returns(100.0);
var otherClass = new OtherClass();
otherClass.Apply((MyState)mock.Object); // after casting, mock.Object.SomeValue returns 0
...
}
If you are trying to test Apply
method, and you have dependency on MyState
which you want to mock - and since you don't want to change it - answer is simple - you can't.
Only interfaces or virtual members. End of story.
But I guess the problem lies in creation of List<Thing>
. I would use AutoFixture nuget package for that. Then it would become really simple:
var fixture = new Fixture();
var things = fixture.Build<Thing>()
.With(x => x.Value, 3) // for each created Thing set the Value to 3
.CreateMany(3) // create 3 things
.ToList();
var state = fixture.Create<MyState>();
state.Things = things;
// Now you know that state.SomeValue should equal to 9.
// To further simplify, you can always sat Value on
// Thing to 0 in the test, then you know state.SomeValue
// would be always 0, regardless of number of items.