More on Fakes – the beta has issues

Testing
5087

Thanks to Peter Provost for helping answer a couple of questions I had about Fakes – you can look at some of my code in my previous posts about using Fakes with the TFS API.

There were two scenarios that I hit snags with. The first was faking methods in a class that are actually defined on the class’s base class. The second was faking an ObservableCollection.

Faking Base Class Methods

Consider this code:

[TestMethod]
public void BaseMethodWontWorkInBeta()
{
using (ShimsContext.Create())
{
var shimWorkItemStore = new ShimWorkItemStore();
var shimTfsTeamProjectCollection = new ShimTfsTeamProjectCollection();
var shimTfsConnection = new ShimTfsConnection(shimTfsTeamProjectCollection);
shimTfsConnection.GetServiceOf1(() => shimWorkItemStore);

var workItemStore = shimTfsTeamProjectCollection.Instance.GetService();

Assert.AreSame(shimWorkItemStore.Instance, workItemStore);
}
}

The exercise here is to try to fake the TfsTeamProjectCollection.GetService method. However, we can’t do it directly on the TfsTeamProjectCollection object, since the method is defined in its base class, TfsConnection.


In line 8, we’re using the ShimTfsConnection constructor that takes in an instance of its child class (the TfsTeamProjectCollection) in order to override the method in the child class. This should work, but Peter told me that this doesn’t work in the Beta – it’ll work when the next release of fakes comes out. The workaround is to use the ShimTfsConnection.AllInstances class to override the GetService method (see my earlier posts where I show how to do this).


Faking ObservableCollection


Let’s look at some more code:

[TestMethod]
public void BindWontWorkBecauseOfObservableCollectionInBeta()
{
using (ShimsContext.Create())
{
var ss = new StubISharedStep();
var sharedStepReference = new StubISharedStepReference
{
FindSharedStep = () => ss
};

var actions = new List
{
sharedStepReference
};

var fakeTestActions = new ShimTestActionCollection();
fakeTestActions.Bind((IList)actions);

Assert.AreEqual(1, fakeTestActions.Instance.Count);

var ssr = (ISharedStepReference)(fakeTestActions.Instance[0]);
Assert.AreSame(sharedStepReference, ssr);

Assert.AreSame(ss, ssr.FindSharedStep());
}
}

The point of this code is to try to fake a TestActionCollection, which is an ObservableCollection. I had successfully managed to fake other collections that were not ObservableCollections (like a WorkItemCollection), and to do that I used the Bind() method of the Shim to bind the fake collection to a list of items. However, I couldn’t get the code to work on the ObservableCollection. (In the above code, I get a NullReferenceException on line 18 when calling the Bind() method.


Peter confirmed that the reason for this is twofold: one, I hadn’t added Fakes for System, which is where the ObservableCollection class resides. This is a performance optimization that the Fakes creation employs so that they don’t create fakes for classes that you’ll never use.


Secondly, and rather unfortunately, even adding that Fake doesn’t work in the Beta. The Fakes creation uses a white-list to generate fakes in the System namespace, and the ObservableCollection isn’t on the white-list in the Beta. In the next release, the System white-list will be customizable, so I am looking forward to getting my grubby paws on that!


Unfortunately, this scenario has no work-around in the Beta, so if you’re trying to Fake an ObservableCollection, you’ll have to wait for the next release of Fakes.


I really like the Fakes framework and what it can do for testing, so I am looking forward to seeing what else comes out of the woodwork.


Happy faking!