Isolator AAA: Creating Fakes

So let’s start at the beginning. And in the beginning you do this:

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

That’s it, you created a fake of the type RealLogger. On this fake you can set behavior and verify methods. In addition, this is an object which you can call methods on. It is similar to MockManager.MockObject<> API in reflective, or RecorderManager.CreateMockedObject<>() in Natural.

The Future

Now, if you supplement it with the following line:

Isolate.Swap<RealLogger>().With(fake);

You swap the next instance of RealLogger that will be created with the fake. Which is similar to MockManager.Mock<>() in Reflective and a new statement inside the recording block in Natural Mocks.

You cannot use WhenCall or Verify on a real object – only on objects that went through the Instance method. So in the case of our future swapped object, the test will look like this:

[TestMethod]
[Isolated]
public void FutureInstance_VerifyMethodWasCalledAndStubbed()
{
  RealLogger fake = Isolate.Fake.Instance<RealLogger>();
  Isolate.Swap<RealLogger>().With(fake);

  Isolate.WhenCalled(() => fake.Increment()).IgnoreCall();

  RealLogger logger = new RealLogger();
  logger.Increment();

  Isolate.Verify.WasCalledWithAnyArguments(() => fake.Increment());
}

And if you call this instead of the last line, you’ll receive an exception:

Isolate.Verify.WasCalledWithAnyArguments(() => logger.Increment());

Note that the Swap statement can be anywhere after Instance, and doesn’t have to follow immediately. If you replace the Swap and WhenCalled lines in our small example, the result will be the same.

Creation

When calling Instance you can decide by the parameter you send it, what would be the default of the current or future instance behavior. The full signature looks like this:

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

Here are the options you have (which can be later overridden per method using WhenCalled):

    • Members.MustSpecifyReturnValues:The default, which is equivalent to the overload with no parameters. All void methods are ignored. If you don’t use WhenCalled on methods that return values, and call them, you will get an exception.
    • Members.CallOriginal: All methods are called by their original implementation.
    • Members.ReturnNulls: All void methods are ignored. Any method that returns referencees will return null. Value type methods return zeros.
    • Members.ReturnRecursiveFakes: All void methods are ignored. Any method that returns referencees will return fakes, on which any method that returns references will return fakes, on which…. you get the point.

 

Recursive Fakes

The final one is pretty powerful. If you have a hierarchy of objects, and you don’t want to write a set of WhenCalled for every item in the hierarchy (SharePoint anyone?), now you don’t have to. Just specify a recursive fake on your top object.

For example, below fake is recursively faked. We want a specific behavior on the return value of its GetSon() method, so we use WhenCalled. What you don’t see here is that all other methods (and their children and grandchildren) are also faked. We can write our test and concentrate on what we need, not everything else.

[TestMethod]
[Isolated]
public void RecursiveStubsWithExpectationOnSecondLevel()
{
  RealLogger fake = Isolate.Fake.Instance<RealLogger>(Members.ReturnRecursiveFakes);
  SonOfLogger son = fake.GetSon();

  Isolate.WhenCalled(() => son.DoSomething(1)).WillReturn(13);

  Assert.AreEqual(13, son.DoSomething(10));
  Isolate.Verify.WasCalledWithAnyArguments(() => son.DoSomething(10));
}
TOP