I comprised this reproduction from real code. You will have to take for granted that in the real code this would be a valid test; this just demonstrates the bug.
Classes under test:
public class OwningObject
{
public OwningObject()
{
SomeList = new List<CollectionObjectType>();
}
public List<CollectionObjectType> SomeList { get; set; }
}
public class CollectionObjectType
{
public string Message { get; set; }
}
Test that demonstrates the bug:
[Isolated(), TestMethod()]
public void TestWhereYouNeedToFakeObjectButUseListWithCallsOriginal()
{
//Arrange
OwningObject target = Isolate.Fake.Instance<OwningObject>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => target.SomeList).CallOriginal();
//Thankfully setter isn't private otherwise I don't know how we would do this!
Isolate.WhenCalled(() => { target.SomeList = null; }).CallOriginal();
target.SomeList = new List<CollectionObjectType>();
//Has to be called after we manually initialize property in above lines
Assert.AreEqual<int>(0, target.SomeList.Count);
Isolate.WhenCalled(() => target.SomeList.Add(null)).CallOriginal();
//Because of Isolateor CallOriginal bug
Assert.AreEqual<int>(1, target.SomeList.Count);
target.SomeList.Clear();
//Act - some method that will be adding a value to the list through the owning object
target.SomeList.Add(new CollectionObjectType() { Message = "TEST" });
//Assert
Assert.AreEqual<int>(1, target.SomeList.Count);
Assert.AreEqual<string>("TEST", target.SomeList[0].Message);
}
Bug - Isolator shouldn't need to RUN the code in order to mark that the original should be called. We know that it is being ran because if we remove the 'target.SomeList.Clear()' line we'll have 2 items in the list when we assert for 1. We can also tell this because of the line I added that asserted that after adding the CallOriginal code we have an item in the list and before CallOriginal we had 0. Without the CallOriginal the functionality of Add will not work because of ReturnRecursiveFakes. In real world test that this is modeled after we need ReturnRecursiveFakes for all the other properties that are examined in the test so it's not an option to not use ReturnRecursiveFakes