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
It's great, thank you. Very usefull.
ReplyDeleteI think it is complex solution. You can implement the same behavior with this code:
ReplyDeleteagreementsManager.Setup(f => f.Create()).Returns(()=>new DrugAgreement());
Now every call to mock will perform function and we will recieve new DrugAgreement on every call.