Click here to Skip to main content
15,884,472 members
Articles / All Topics

Introduction to Fakes and Migration from Moles

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
4 Oct 2012CPOL6 min read 16.4K   7   3
Fakes is a new test isolation framework from Microsoft. It resembles and is inspired by Moles Research project. This post introduces Fakes and describes the migration from Moles.

Fakes is a new test isolation framework from Microsoft. It is inspired by and resembles to Moles a framework which I have described in one of my previous blog posts. In this post, I will briefly describe Fakes and then show the steps which have to be taken when migrating from Moles. You will find that the migration itself is not that complicated. Besides some changes in the structure of the project, only few changes are needed in the code.

The code related to this post is available at my GitHub repository.

Fakes framework contains two constructs which can be used to isolate code:

  • Stubs – should be used to implement interfaces and stub the behavior of public methods.
  • Shims – allow mocking the behavior of ANY method, including static and private methods inside .NET assemblies.

Stubs are generated classes. For each public method in the original interface, a delegate is created which holds the action that should be executed while invoking the original method. In the case of Shims, such delegate is generated for all methods, even the private and static ones.

When using Stubs, you provide mocked implementation of any interface to the class or method which you are testing. This is done transparently before compilation and no changes are made to the code after the compilation. On the other hand, Shims use the technic called IL weaving (injection of MSIL assembly at runtime). This way, the code which should be executed is replaced at runtime by the code provided in the delegate.

The framework has caused some interesting discussions across the web. The pluralsight blog has found some negative points Rich Czyzewski describes how noninvasive tests can be create while using Fakes. And finally, David Adsit nicely summarizes the benefits and the possible usage of the Fakes. From what has been said on the net, here is a simple summary of negative and positive points.

Pros

  • Lightweight framework, since all the power of this framework is based only on generated code and delegates
  • Allows stubbing of any method (including private and static methods)
  • No complicated syntax. Just set the expected behavior to the delegate and you are ready to go
  • Great tool when working with legacy code

Cons

  • The test are based on generated code. That is to say, a phase of code generation is necessary to create the “stubs”.
  • No mocking is built-in into the framework. There is no built-in way to test whether a method has been called. This however can be achieved by manually adding specific code inside the stubbed method.

Migrating from Moles to Fakes

First a small warning, a bug was apparently introduced by the Code Contracts team, which causes a crash when building a solution which uses Fakes. You will need to install the latest version of Code Contracts. (If you do not know or use Code Contracts, you should not be impacted).

If you have already used Moles before, you might be wondering, how much code changes will the migration need. To give you a simple idea, I have migrated the code from my previous post about Moles in order to use Fakes. Two major steps have to be taken during the migration:

  • Change the structure of the project and generate new stubs
  • Rewrite the unit tests to use newly generated classes

To prepare the solution, we have to remove all the references to Moles as well as the .moles files which were previously used during the code generation by the Moles framework. Next step is the generation of new stubs using Fakes framework. This is as simple as it has been before. Open the references window and right click on the DLL for which you want to generate the stubs. Then, you should be able to select "Add Fakes Assembly” from the menu.

The following images show the difference between the old and new project structure (also note that I was using VS 2010 with Moles and I am now using VS 2012 with Fakes).

image





---------------------->
image

The next step is the code changes.

Rewriting Code using Shims

Here is a classical example of testing a method which depends on DataTime.Now value. The first snippet is isolated using Moles and the second contains the same test using Fakes:

C#
[TestMethod]
[HostType("Moles")]
public void GetMessage()
{
  MDateTime.NowGet = () =>
  {
    return new DateTime(1, 1, 1);
  };
  string result = Utils.GetMessage();
  Assert.AreEqual(result, "Happy New Year!");
}
C#
[TestMethod]
public void GetMessage()
{
 using (ShimsContext.Create())
 {
   System.Fakes.ShimDateTime.NowGet = () =>
   {
    return new DateTime(1, 1, 1);
   };
   string result = Utils.GetMessage();
   Assert.AreEqual(result, "Happy New Year!");
 }
}

The Main Differences

  • Methods using Shims, do not need the HostType annotation previously needed by Moles.
  • On the other hand, a ShimsContext has to be created and later disposed when the stubbing is not needed any more. The using directive provides a nice way to dispose the context right after its usage and marks the code block in which the system has “stubbed” behavior.
  • Only small changes are needed due to different names generated classes.

Rewriting Code Which Is Using Only Stubs

Here the situation is even easier. Besides the changes in the naming of the generated classes, no additional changes are needed to migrate the solution. The following snippet test “MakeTransfer” method, which takes two accounts as parameters.

The service class containing the method needs Operations and Accounts repositories to be specified in the constructor. The behavior of these repositories is stubbed. This is might be typical business layer code of any CRUD application. First, let’s see the example using Moles.

C#
[TestMethod]
public void TestMakeTransfer()
{
 var operationsList = new List<Operation>();

 SIOperationRepository opRepository = new SIOperationRepository();
 opRepository.CreateOperationOperation = (x) =>
 {
  operationsList.Add(x);
 };

 SIAccountRepository acRepository = new SIAccountRepository();
 acRepository.UpdateAccountAccount = (x) =>
 {
  var acc1 = _accounts.SingleOrDefault(y => y.Id == x.Id);
  acc1.Operations = x.Operations;
 };

 AccountService service = new AccountService(acRepository, opRepository);
 service.MakeTransfer(_accounts[1], _accounts[0], 200);
 Assert.AreEqual(_accounts[1].Balance, 200);
 Assert.AreEqual(_accounts[0].Balance, 100);
 Assert.AreEqual(operationsList.Count, 2);
 Assert.AreEqual(_accounts[1].Operations.Count, 2);
 Assert.AreEqual(_accounts[0].Operations.Count, 3);
}

Note the way the repository methods are stubbed. Due to the fact that the stubs affect the globally defined variables (the list of operations, and the list of accounts), we can make assertions on these variables. This way, we can achieve “mocking” and be sure that the CreateOperation method and the UpdateAccount method of Operation and Account repository have been executed. The operationsList variable in this example acts like a repository and we can easily Assert to see if the values have been changed in this list.

Let’s see the same example using Fakes:

C#
[TestMethod]
public void TestMakeTransfer()
{
 var operationsList = new List<Operation>();

 StubIOperationRepository opRepository = new StubIOperationRepository();
 opRepository.CreateOperationOperation = (x) =>
 {
  operationsList.Add(x);
 };

 StubIAccountRepository acRepository = new StubIAccountRepository();
 acRepository.UpdateAccountAccount = (x) =>
 {
  var acc1 = _accounts.SingleOrDefault(y => y.Id == x.Id);
  acc1.Operations = x.Operations;
 };

 AccountService service = new AccountService(acRepository, opRepository);
 service.MakeTransfer(_accounts[1], _accounts[0], 200);
 //the asserts here....
}

You can see that the code is almost identical. The only difference is in the prefix given to the stubs (SIAccountRepository becomes StubIAccountRepository). I am almost wondering if Microsoft could not just keep the old names, then we would just need to change the using directive…

Fakes & Pex

One of the advantages of Moles compared to other isolation frameworks, was the fact that it was supported by Pex. When Pex explores the code, it enters deep into any isolation framework which is used. Since Moles is based purely on delegates, Pex is able to dive into the delegates and generated tests according the content inside the delegates. When using another isolation framework, Pex will try to enter the isolation framework itself, and thus will not be able to generate valid tests.

So now, when Fakes are here as replacement of Moles, the question is whether we will be able to use Pex with Fakes? Right now, it is not possible. Pex add-on for Visual Studio 11 does not (yet) exists and I have no idea whether it will ever exist.

I guess Pex & Moles were not that adopted by the community. On the other hand, both were good tools and found their users. Personally, I would be glad if Microsoft continued the investment into Pex and automated unit testing though I will not necessarily use it everyday in my professional projects. On the other hand, I would always consider it as an option when starting a new project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Junior) OCTO Technology
Czech Republic Czech Republic
Writing software at ITG RFQ-hub.
LinkedIn
Blog
GitHub
Articles at OCTO blog

Comments and Discussions

 
QuestionFYI: Fakes requires VS 2012 Ultimate addition Pin
AlGonzalez7-Oct-12 7:44
AlGonzalez7-Oct-12 7:44 
AnswerRe: FYI: Fakes requires VS 2012 Ultimate addition Pin
Xantilon16-Sep-15 18:10
professionalXantilon16-Sep-15 18:10 
GeneralRe: FYI: Fakes requires VS 2012 Ultimate addition Pin
AlGonzalez17-Sep-15 2:55
AlGonzalez17-Sep-15 2:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.