How to Setup a readonly property with Moq?
Asked Answered
C

2

15

I am trying to unit test using Moq. Here is the example code:

public class ConcreteClass
{
    private readonly FirstPropery firstProperty;
    private readonly SecondProperty secondProperty;

    public ConcreteClass(firstProperty, secondProperty)
    {
        this.firstProperty = firstProperty;
        this.secondProperty = secondProperty;
    }
}

[TestMethod]
    var concreteClassMock = new Mock<ConcreteClass>() { CallBase = true };

In my test method, I want to set firstProperty to reference a real object FirstProperty object (created by a factory), and later use it to test another object's behavior. Is there any way to achieve that?

Clower answered 15/8, 2016 at 8:55 Comment(1)
You don’t mock private stuff. A mock should be independent of some implementation.Root
R
9

Usually, you wouldn’t mock private members since you are only mocking the public interface of something. A mock is thus completely independent of implementation details.

That being said, you can pass constructor arguments to the Mock constructor that will then be passed on to the target’s constructor:

new Mock<ConcreteClass>(firstProperty, secondProperty) {CallBase = true};

However, if your goal is to actually test the ConcreteClass, you should not create a mock of it. You should test the actual object. So mock its dependencies and pass those if necessary, but keep the object you want to test actually real. Otherwise, you might introduce and test behavior that comes from the mock instead of the object you are testing:

var firstMock = new Mock<FirstProperty>();
var secondMock = new Mock<FirstProperty>();

var obj = new ConcreteClass(firstMock.Object, secondMock.Object);

obj.DoSomething();
// assert stuff
Root answered 15/8, 2016 at 9:8 Comment(3)
What's the difference between mocking concrete class, passing parameters via constructor and simple "new ConcreteClass(param1, param2) ? I'm talking about scenario when you actually need to mock an object that sets its readonly property in the constructor. Then you want to pass this mocked object to the object that will be tested. Why not just "newing it up"?Euphorbiaceous
@LouisaBickley I’m not entirely sure what you mean; but it depends on what you want to test. If you want to test the constructor of class X, then you shouldn’t mock it, since mocking “replaces” the actual implementation by your mocked behavior. And if you want to test a different class Y that depends on X, then you should mock X so the implementation details of X do not affect the tests for Y. – Maybe you can open up a new question, so we can go a bit more into the details for this?Root
This seems to be the only solution available for immutable objects.Sarre
J
10

A few remarks:

1- It could be easily achieve with an interface and a get method like this:

public interface IConcreteClass
{
    FirstProperty FirstProperty { get; }
}

    [Test]
    public void TestCase()
    {
        var yourFirstPropertyImplementation = new FirstProperty();
        var concreteClassMock = new Mock<IConcreteClass>();
        concreteClassMock.Setup(o => o.FirstProperty).Returns(yourFirstPropertyImplementation);
    }

2- Depending of your scenario, do you really need a Moq, why not just use the true implementation and use moq only at boundaries?

3- You should clarify what you want to test? If it's concrete class? or the properties? or some other classes? The test case I propose in 1 is valid only to test the interaction of concrete class with some other classes.

Juanjuana answered 15/8, 2016 at 9:7 Comment(0)
R
9

Usually, you wouldn’t mock private members since you are only mocking the public interface of something. A mock is thus completely independent of implementation details.

That being said, you can pass constructor arguments to the Mock constructor that will then be passed on to the target’s constructor:

new Mock<ConcreteClass>(firstProperty, secondProperty) {CallBase = true};

However, if your goal is to actually test the ConcreteClass, you should not create a mock of it. You should test the actual object. So mock its dependencies and pass those if necessary, but keep the object you want to test actually real. Otherwise, you might introduce and test behavior that comes from the mock instead of the object you are testing:

var firstMock = new Mock<FirstProperty>();
var secondMock = new Mock<FirstProperty>();

var obj = new ConcreteClass(firstMock.Object, secondMock.Object);

obj.DoSomething();
// assert stuff
Root answered 15/8, 2016 at 9:8 Comment(3)
What's the difference between mocking concrete class, passing parameters via constructor and simple "new ConcreteClass(param1, param2) ? I'm talking about scenario when you actually need to mock an object that sets its readonly property in the constructor. Then you want to pass this mocked object to the object that will be tested. Why not just "newing it up"?Euphorbiaceous
@LouisaBickley I’m not entirely sure what you mean; but it depends on what you want to test. If you want to test the constructor of class X, then you shouldn’t mock it, since mocking “replaces” the actual implementation by your mocked behavior. And if you want to test a different class Y that depends on X, then you should mock X so the implementation details of X do not affect the tests for Y. – Maybe you can open up a new question, so we can go a bit more into the details for this?Root
This seems to be the only solution available for immutable objects.Sarre

© 2022 - 2024 — McMap. All rights reserved.