Hi, I'm looking for guidance regarding a weird Fake behavior I've come upon.
In order to promote code reuse between TestMethods, I have the habit of creating a "TestFixture" private class within my test classes, like so:
[TestMethod, Isolated]
public class AwesomeTest
{
[TestMethod]
public void DoIt_WhenWhatever_ShouldReturnTrue()
{
// Arrange
var fixture = new AwesomeTestFixture();
fixture.SetupSomeCommonExpectations();
var awesomeThing = fixture.CreateAwesome();
// Act
var result = awesomeThing.DoIt();
// Assert
Assert.IsTrue(result);
}
private class AwesomeTestFixture
{
public AwesomeTestFixture()
{
this.DependencyA = Isolate.Fake.Instance<DependencyA>();
this.DependencyB = Isolate.Fake.Instance<DependencyB>();
}
public DependencyA DependencyA { get; set; }
public DependencyB DependencyB { get; set; }
public void SetupSomeCommonExpectations()
{
// ...
}
public Awesome CreateAwesome()
{
return new Awesome(this.DependencyA, this.DependencyB);
}
}
}
With this pattern, I don't have to create TestClass-specific fields that would need to be reset during each TestInitialize in order to prevent state from leaking between TestMethods.
However, I've come upon the following problem. Say I want to set a property value on my DependencyA fake:
public void SetupSomeCommonExpectations()
{
this.DependencyA.SomeBoolean = true; // NullRef on SomeBoolean
}
Contrary to what I expected, the above breaks with a NullReferenceException. I assume this is because once the fake instance has been assigned to the TestFixture property, then it cannot be used for expectations anymore. A NullRef also happens if I try to add complementary expectation to a TestMethod:
[TestMethod]
public void DoIt_WhenWhatever_ShouldSetSomeBooleanToTrue()
{
// Arrange
var fixture = new AwesomeTestFixture();
fixture.SetupSomeCommonExpectations();
fixture.DependencyA.SomeBoolean = false; // BOOM NullRef
var awesomeThing = fixture.CreateAwesome();
// Act
var result = awesomeThing.DoIt();
// Assert
Assert.IsTrue(fixture.DependencyA.SomeBoolean); // This is what I would be trying to validate
}
There seems to be no real way to go around this limitation, except to do all my expectations on the initial reference to the Fake:
private class AwesomeTestFixture
{
public AwesomeTestFixture()
{
}
public DependencyA DependencyA { get; set; }
public void SetupSomeCommonExpectations()
{
var dependencyA = Isolate.Fake.Instance<DependencyA>();
dependencyA.SomeBoolean = true; // this works
this.DependencyA = dependencyA;
}
public Awesome CreateAwesome()
{
return new Awesome(this.DependencyA);
}
}
However, this still prevents me from adding more property expectations on the DependencyA instance from within my TestMethod, making my whole TestFixture pattern slightly unwieldy.
Basically, trying to indirectly setup a mock object by accessing it through a property doesn't seem to be supported. I'm looking for a technical explanation as to why a mocked object cannot be held temporarily in another object's property between separate expectation recordings.
Thanks for your help!