About Me

Tuesday, February 22, 2011

How to make Moq object to return different values on each invocation

Today I stacked with the issue how to make Moq function to return different values when its calling by testing unit.

Let's see on example:
[Test]
public void Value_should_be_assigned_on_property_value()
{
///Arrange
...
DrugAgreement agreement = new DrugAgreement();

agreementsManager.Setup(f => f.Create()).Returns(agreement);

///Action
testingUnit.AssignPropertyOnNewlyCreatedObject("propertyValue");

///Assert
Assert.AreEqual("propertyValue", agreement.TestingProperty);
}

The code above expecting that the testing unit will create new instance of the object by calling Create, and change its TestingProperty value to propertyValue

Now, let's implement the code for it:
public DrugAgreement AssignPropertyOnNewlyCreatedObject(string newValue) {
    var obj = manager.Create();
    obj.TestingProperty = newValue;
    return obj;
}

The code above will work as expected.
Now imagine that we mistakenly called Create for the second time after the property was set:
public DrugAgreement AssignPropertyOnNewlyCreatedObject(string newValue) {
    var obj = manager.Create();
    obj.TestingProperty = newValue;
    obj = manager.Create();
    return obj;
}

For the first look, the test above should fail, but it is not!
The test says that TestingProperty is equal to propertyValue, but the object is different. We called Create for the second time and expecting that manager is stateless and don't remember previously returned instance.
The answer is simple - our mock manager returns the same instance of object every time when Create is calling.

So, how to test this ?
How to make sure that Create method is stateless and always returns different objects?

Here is the corrected test:

[Test]
public void Value_should_be_assigned_on_property_value()
{
    ///Arrange
    ...
    DrugAgreement agreement = new DrugAgreement();

    agreementsManager.Setup(f => f.Create()).Returns(agreement).Callback(()=> agreement = new DrugAgreement());

    ///Action
    testingUnit.AssignPropertyOnNewlyCreatedObject("propertyValue");

    ///Assert
    Assert.AreEqual("propertyValue", agreement.TestingProperty);
}

If we test our code now it will fail as it should.
As you can see, the difference in the test is in calling Callback function by moq manager . That function instantiates new instance of DrugAgreement class after each call.

In this case our manager is really stateless and always return different instances

2 comments:

  1. It's great, thank you. Very usefull.

    ReplyDelete
  2. I think it is complex solution. You can implement the same behavior with this code:

    agreementsManager.Setup(f => f.Create()).Returns(()=>new DrugAgreement());

    Now every call to mock will perform function and we will recieve new DrugAgreement on every call.

    ReplyDelete