Writing Shorter Tests – Don’t Build the Tree

Richard Fennel of Black Marble wrote a great post about using Isolator for faking Workflow Foundation with SharePoint. It’s a good example of how to use Isolator with those technologies.

And, there is always some room for improvement, and in our case it’s my favorite – making the test shorter. Using the now default Members.ReturnRecursiveFakes, allows us to fake an entire tree of objects in a single line. We don’t need to build the tree ourselves, rather pick things from the tree.

Here’s a snippet from the example in Richard’s post:

 // Create our fake workflow and items
var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>(Members.ReturnRecursiveFakes);

var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);
var fakeField = Isolate.Fake.Instance<SPField>(Members.ReturnRecursiveFakes);

fakeField.DefaultValue = false.ToString();

Isolate.WhenCalled(() => fakeProperties.Item).WillReturn(fakeItem);
Isolate.WhenCalled(() => fakeItem.Title).WillReturn("ABC");

Isolate.WhenCalled(() => fakeItem["Approved"]).WillReturn(fakeField);

This is Isolator’s Arrange part of the code. The first tip is to remove Members.ReturnRecursiveFakes from the code, as it is the default, when using Isolate.Fake.Instance.

As you can see, there are four lines here that are used to build the object tree:

var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);
var fakeField = Isolate.Fake.Instance<SPField>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => fakeProperties.Item).WillReturn(fakeItem);
Isolate.WhenCalled(() => fakeItem["Approved"]).WillReturn(fakeField);

By setting a return value on the Item property, I’m building the object tree. And the same on the indexer of the item. But since Isolator already built that tree for us, we can just pick the object from the tree (I really like the metaphor, noticed?):

var fakeItem = fakeProperties.Item;
var fakeField = fakeItem.Fields["Approved"];

Both are fake objects, and I can set the behavior on them directly. The final snippet looks like this:

 // Create our fake workflow and items
var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>();

var fakeItem = fakeProperties.Item;
Isolate.WhenCalled(() => fakeItem.Title).WillReturn("ABC");

var fakeField = fakeItem.Fields["Approved"];
fakeField.DefaultValue = false.ToString();

See, much shorter (2 lines out of 7, almost 30%). I like short. Less bugs, and tests are less likely to break, not to say are more readable.

And one final tip. Notice that for fakeItem.Title we use WhenCalled, but for DefaultValue we just set the value? Setting a value into a fake object is like using WhenCalled on the getter, only nicer – it’s called TrueProperties. However, it works only if the property has a setter AND a getter. Unfortunately for us, the Title property is read-only, and so we need to use WhenCalled on it. Too bad, but that’s SharePoint for you.

  • Shay Jacoby

    Thanks

  • Eli Lopian

    I am not sure this will work
    fakeField = fakeItem["Approved"];

    as there is no index set, but this will work (removing yet another line)

    Isolate.WhenCalled(()=>fakeItem["Approved"].DefaultValue).WillReturn(false.ToString());

  • Gil Zilberfeld

    Actually, it does not work because of using the wrong indexer. It should be the fakeItems.Fields["Approved"] indexer, which now appears in the post.
    And of course, chaining the methods, as suggested also works. This is more about readability preferences.

TOP