Welcome to Typemock Answers. Here you can ask and receive answers from other community members. And if you liked or disliked an answer or thread: react with an up- or downvote Enjoy!

Query over faking collections

+2 votes
I have been doing some development where I need to mock out a TFS server and I have come against an issue with mocking some of the collections. I have worked round it, but am interested to know what is happening, if anyone knows.

In general for mocking TFS collections I have created a List<T> and swapped it in as follows

var fakeTypes = new List<WorkItemType>();
for (int count = 0; count < 2; count++)
   var fakeType = Isolate.Fake.Instance<WorkItemType>(Members.ReturnRecursiveFakes);
   Isolate.WhenCalled(() => fakeType.Name).WillReturn(string.Format("Type {0}", count));

// using a previous created fakeStore
Isolate.WhenCalled(() => fakeStore.Projects["Project 0"].WorkItemTypes).WillReturnCollectionValuesOf(fakeTypes);

In most cases this form works, I can iterate through the collection.

 foreach (WorkItemType item in project.WorkItemTypes)
       // do something
       var name = item.Name;

However in the particular case of the WorkItemTypes this did not work, it compiles, but the loop was never entered i.e. the collection was empty.

I found that the following form of fake object creation works

var fakeCollection = Isolate.Fake.Instance<WorkItemTypeCollection>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => fakeStore.Projects["Project 0"].WorkItemTypes).WillReturn(fakeCollection);

// now we set the responses when each item is called
// using the list<T> create at the start
Isolate.WhenCalled(() => fakeCollection[0]).WillReturn(fakeTypes[0]);
Isolate.WhenCalled(() => fakeCollection[1]).WillReturn(fakeTypes[1]);

This form does work for WorkItemTypeCollection, so my question is what is the recommended way mock collections, should both of these forms work or is there a good reason why the first form fails in some cases
asked Jan 27, 2009 by rfennell (1,940 points)

2 Answers

+2 votes

Basically there are a few ways to fake collection values. Lets go over them one by one:

1. Simply returning the list - if you can instantiate a concrete list and you are not interested in faking it, but rather using custom test data in the list you can simply fake the call to the list getter:
var fakeType = Isolate.Fake.Instance<WorkItemType>();
Isolate.WhenCalled(() => project.WorkItemTypes).WillReturn(new List<WorkItemTypes> { fakeType });

2. Using WillReturnCollectionValuesOf - when you cannot instantiate the collection you can fake it with values from another collection you can create more easily (in this case a simple array):
Isolate.WhenCalled(() => project.WorkItemTypes).WillReturnCollectionValuesOf(new[] { fakeType });

3. Setting expectations on the collection indexers - this implicitly creates the underlying collection for you:
Isolate.WhenCalled(() => project.WorkItemTypes[0]).WillReturn(fakeType);
// or
Isolate.WhenCalled(() => project.WorkItemTypes[0].Name).WillReturn("Type 0");

So, which technique to use? the first one is probably the most straightforward, and the third is very intuitive to read. Use the second option if you need to directly replace an entire collection with test data, and you can't instantiate that collection type.

Hope this helps,
Typemock Support
answered Jan 27, 2009 by doron (26,680 points)
+2 votes
Yes that makes the choice clearer, it is down to if I either need to (or can) instantiate that collection type.

Thanks for clearing that up
answered Jan 28, 2009 by rfennell (1,940 points)