Welcome to Typemock Q&A, where you can ask questions and receive answers from other members of the community.

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));
   fakeTypes.Add(fakeType);
}

// 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 26, 2009 by rfennell (1,020 points)

2 Answers

+2 votes
Hi,

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,
Doron
Typemock Support
answered Jan 27, 2009 by doron (16,060 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 27, 2009 by rfennell (1,020 points)
...