Isolator AAA: Setting Behavior

After we created fakes, now we can set specific behavior. As you may recall, the default behavior is set when the fake is created. Using the WhenCalled API, we can now set the behavior of a specific method.

Setting a method looks like this:

RealLogger fake = Isolate.Fake.Instance<RealLogger>();
Isolate.WhenCalled(() => fake.Increment()).IgnoreCall();

Note that the WhenCalled clauses are sort of a default behavior for the method. Read the last line as: “From now on, for every Increment method, ignore the call”. In the future we’ll be adding repeats and conditionals.

Things you can do with WhenCalled:

    • CallOriginal – Calls the original implementation.
    • WillThrow – Throws a specific exception
    • IgnoreCall – Ignores the real implementation (for void methods only).
    • WillReturn – Ignores the real implementation and returns a value (for non-void methods only)

 

Because of the type of the value returned (or void if not), you can only set appropriate behavior per this return type. If this is a void method, you cannot call WillReturn on it. And in the same manner, if it returns something, you can’t use IgnoreCall. This is prevented at compile time, which is very handy.

Use WhenCalled, along with the Fake creation smartly, and you can save yourself precious lines of code. Here’s an example:

RealLogger fake = Isolate.Fake.Instance<RealLogger>(Members.CallOriginal);
Isolate.WhenCalled(() => fake.Increment()).IgnoreCall();

Note that we’re using Members.CallOriginal for our fake, which sets the default behavior for calling all methods as-is. But for a single method, I’m setting IgnoreCall behavior. If you want a whole fake object and ancestry, and only one method should be return a set value, you can use this:

RealLogger fake = Isolate.Fake.Instance<RealLogger>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => fake.IntCall()).WillReturn(15);

The final trick is to use chains. Behold this magnificent example:

[TestMethod]
[Isolated]
public void ChainingRecursiveMockExpectations()
{
  RealLogger fake = Isolate.Fake.Instance<RealLogger> (Members.ReturnRecursiveFakes);
  Isolate.WhenCalled(()=>fake.Instance().Instance().GetSon().DoSomething(1)).WillReturn(20);

  Assert.AreEqual(20, fake.Instance().Instance().GetSon().DoSomething(1));
}

The fake is recursive. Note that we set the behavior on a chain of calls. The entire chains returns 20. A regular DoSomething() doesn’t.

The same works for verifying calls, which is the subject off the next post.

Want to start unit testing? Take advantage of our 30-day FREE trial of Isolator Complete. Get it now

  • woonboo

    For the chaining method; it’s hard for me to follow exactly what you’re doing there.

    Could you break that down into something bite size for a newb?

    Thanks!

  • Doron

    @woonboo

    The chaining here is confusing mainly because it was borrowed from our test classes which have shaky ‘business logic’ per say.

    Looking at this chain (fake.Instance().Instance().GetSon().DoSomething(1)) here’s what happens:
    fake is an instance of the RealLogger class. We call the Instance method for it – it’s a member function of the RealLogger class that returns a RealLogger. We use the object it returned and call its Instance() method – we can do that because it’s a RealLogger as well. Theoretically, we could keep chaining .Instance().Instance() for ever, but instead we call GetSon(). GetSon() is another member function of the RealLogger class which returns another object type – we called that SonOfLogger. We then call DoSomething() which is a member function of the SonOfLogger class which returns an integer.

    This chain can be resolved as:
    RealLogger x = fake.Instance();
    RealLogger y = x.Instance();
    SonOfLogger z = y.GetSon();
    int result = z.DoSomething(1);

    I hope this clears things up.

TOP