Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Moq to set values for fields?

Tags:

c#

.net

mocking

moq

I have a dependency that I would like to mock.

public abstract class MyDependency
{
    protected Dictionary<string, object> _outputs = new Dictionary<string, object>();
    public Dictionary<string, object> Outputs
    {
        get
        {
            return _outputs;
        }
    }
}

I need the public property Outputs to return a known value for the purpose of my unit test. I know that we cannot mock fields or non-virtual members. So, I could go and create my own mocked MyDependency that sets the backing field _outputs:

public class MockMyDependency : MyDependency
{
    public MockMyDependency()
    {
        _outputs = new Dictionary<string, object>
        {
            { "key", "value" }
        };
    }
}

However, is it possible to use Moq to do this without explicitly creating my own derived mock class?

like image 925
Stephen Booher Avatar asked Apr 09 '13 19:04

Stephen Booher


2 Answers

If you don't derive from the class yourself, it's pretty hard to specify the protected field _outputs because it's not in scope and its name will not compile.

But you can do it with nasty reflection of course:

var mock = new Mock<MyDependency>();

var field = typeof(MyDependency)
    .GetField("_outputs", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(mock.Object,
    new Dictionary<string, object> { { "key", "value" } });

If you do derive from MyDependency after all, then inside the class that derives from it, you can set the field directly, as in:

// this code is inside some class which derives from MyDependency
mock.Object._outputs = new Dictionary<string, object> { { "key", "value" } };
like image 25
Jeppe Stig Nielsen Avatar answered Sep 26 '22 20:09

Jeppe Stig Nielsen


If you cannot change the property to be virtual or define an interface (I assume if you can't do the first one you won't be able to do the second one either) then I see only two possible options:

  • Use a mocking framework that does support mocking of non virtual members (e.g. TypeMock)
  • Create a specific mock implementation that inherits from MyDependency as you already did.
like image 178
treze Avatar answered Sep 23 '22 20:09

treze