One of the new features in Isolator 5.1.1 is fixing an old issue. Let’s say I have a collection I’d like to fake. I use the following:
1 |
MyCollection coll= Isolate.Fake.Instance<MyCollection>(); |
What happens when I try to do the following?
1 |
<span class="kwrd">foreach</span> (item <span class="kwrd">in</span> coll)<br />{<br /> Console.WriteLine(item.Price);<br />} |
The foreach statement, actually calls the collection’s method GetEnumerator, which returns an IEnumerator implementer. Makes sense, but what does it really return? It’s an enumerator that “knows” how to enumerate its parent. But what happens for a fake collection? Even if it does return something, the object returned is usually a fake also. It doesn’t have any knowledge about the fake parent, and if it calls on some of the parent’s methods we’ll probably come to a screeching exception halt.
But let’s get back to what I want to solve: I want a collection, that although it’s a fake, still acting like a collection. That means for a for-each, I want to return my custom values. And not crash, which is also a reasonable requirement.
1 |
Isolate.WhenCalled(() => coll).WillReturnCollectionValuesOf(<span class="kwrd">new</span> List<RealLogger>{item1,item2}); |
The syntax requires a bit more attention than usual. Notice that the WhenCalled Lambda expression contains coll, which is different than the usual method call. With this syntax (which is equivalent to the property get syntax), we identify a collection that we plan to enumerate on. The WillReturnCollectionValuesOf specifies another collection, that will be enumerated when the foreach is invoked on our collection. So in this case, when the foreach clause above runs, it will return two items: item1 and item2.
Let’s take a look at a more advanced case, where a collection is used inside another collection. Here’s some SharePoint code we’d like to test:
1 |
<span class="kwrd">public</span> <span class="kwrd">void</span> DeepIterationWithForEach()<br />{<br /> SPSite site = <span class="kwrd">new</span> SPSite(<span class="str">"http://sharepoint.typemock.com"</span>);<br /> <span class="kwrd">using</span> (SPWeb web = site.OpenWeb())<br /> {<br /> <span class="kwrd">foreach</span> (SPList list <span class="kwrd">in</span> web.Lists)<br /> {<br /> <span class="kwrd">foreach</span> (SPItem item <span class="kwrd">in</span> list.Items)<br /> {<br /> item.Update();<br /> }<br /> }<br /> }<br />} |
Let’s concentrate on the foreach-inside-foreach. SPLists contain SPItems. Here is some test code:
1 |
[TestMethod]<br /><span class="kwrd">public</span> <span class="kwrd">void</span> SwappingSharepointCollections_IterateOverCollectionWithForEach_SwappedIteratorsAreUsed()<br />{<br /> SPSite fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);<br /> Isolate.Swap.NextInstance<SPSite>().With(fakeSite);<br /><br /> Isolate.WhenCalled(() => fakeSite.OpenWeb().Lists[2].Items).WillReturnCollectionValuesOf(<span class="kwrd">new</span> List<SPItem><br /> {<br /> Isolate.Fake.Instance<SPItem>(),<br /> Isolate.Fake.Instance<SPItem>(),<br /> Isolate.Fake.Instance<SPItem>()<br /> });<br /> SharepointUsingClass target = <span class="kwrd">new</span> SharepointUsingClass();<br /> target.DeepIterationWithForEach();<br /><br /> var fakeItemList = fakeSite.OpenWeb().Lists[2].Items;<br /> <span class="kwrd">foreach</span> (SPItem item <span class="kwrd">in</span> fakeItemList)<br /> {<br /> Isolate.Verify.WasCalledWithAnyArguments(() => item.Update());<br /> }<br />} |
After faking SPSite recursively, let’s take a look at the WhenCalled clause. It focuses on fakeSite.OpenWeb().Lists[2].Items, which is the third list in the external collection. In the spirit of “fake everything that you don’t care about“, we don’t care about the first or second list. We care about the 3rd one, and this is where we specify what items we return in the collection. We use the WillReturnCollectionValuesOf to specify the items we want, in our case, a List of fake SPItems. Apart from foreach-ing inside the target method, we also enumerate over the list in the test to Verify the calls.
So now you can fake collections easily with Isolator. If you’d go a step further we’ll get to duck-typing. But that’s another post.
Note that you can click the link to learn more on using SharePoint or to learn how to unit test a SharePoint application
Technorati Tags:
Microsoft , Microsoft sharepoint , Unit Testing SharePoint, mock, Software Testing, Swapping Collections