Showing posts with label Microsoft Fakes Framework. Show all posts
Showing posts with label Microsoft Fakes Framework. Show all posts

Saturday, 12 January 2013

Of Microsoft Fakes, Internal Classes and Signing Keys


Recently there was a question raised in the community about using Microsoft fakes for internal classes and what should be specified in the InternalVisibleTo attribute in the AssemblyInfo file. There was some confusion so I thought it would be useful to write a detailed post about it.

For the purpose of this post, I created a class library (SimpleLibrary.dll) that contain two internal classes:

  1. TextFileReader: Responsible for reading contents from a given text file.
  2. Client: Uses the TextFileReader class.

We will create a simple unit test where we will use generated shims for the TextFileReader class, so that the test is not dependent upon the existence of a text file in the file system. The code for the two classes is as follows:

TextFileReader

namespace SimpleLibrary
{
using System.IO;

internal class TextFileReader{
internal string ReadFile(string fileName)
{
StreamReader file = null;
string text = string.Empty;
try{
file = new StreamReader(fileName);
text = file.ReadToEnd();
}
finally{
if (file != null){
file.Close();
file.Dispose();
}
}
return text;
}
}}

Client 


namespace SimpleLibrary
{
internal class Client {
private TextFileReader fileReader;

internal Client(TextFileReader fileReader){
this.fileReader = fileReader;
}

internal string TestMethod(string fileName){
return fileReader.ReadFile(fileName);
}
}}


As you can see, the TextReaderFile is an internal class with an internal method "ReadFile" and Client is another internal class that depends upon an instance of the TextReaderFile and uses it's "ReadFile" method.

SimpleLibrary.Test


Now lets create a unit test project to test our library, we will call it SimpleLibrary.Test. In order to test our internal classes in the unit test project, we will need to include the "InternalVisibleTo" attribute in the AssemblyInfo.cs file of the SimpleLibrary project as follows:

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("SimpleLibrary.Test")]

Our unit tests can now see the internal classes and we can write unit tests for these. However, if we want to generate fakes for the internal classes, we will also have to include "InternalVisibleTo" attribute for the fakes assembly as well.

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("SimpleLibrary.Fakes")]

Adding the above attribute will allow the generated SimpleLibrary.Fakes class to view internal classes and methods.

Now, we can generate fakes for the library by right clicking on the reference to SimpleLibrary and clicking on the "Add Fakes Assembly" option.

Our very simple unit test is as follows:


namespace SimpleLibrary.Test
{  
using Microsoft.QualityTools.Testing.Fakes;  
using Microsoft.VisualStudio.TestTools.UnitTesting;  
using SimpleLibrary.Fakes;      

[TestClass]      
public class ClientTest  
{      
[TestMethod]
public void TestReadFile()
{
using (ShimsContext.Create()) {

// Arrange
ShimTextFileReader shim = new ShimTextFileReader();              
shim.ReadFileString = (filename) => { return "The file content."; };              
var target = new Client(shim.Instance);              

// Act              
var actual = target.TestMethod(@"C:\somefile.txt");

// Assert              
Assert.AreEqual("The file content.", actual);          
}      
}  }}


The test creates a shim of the TextFileReader class and uses it while calling the TestMethod in the client class.

Strong Named Assemblies:


Now, lets consider that the assembly SimpleLibrary has to be strongly named, so will have to sign the assembly. We do that by generating a key file "SimpleLibraryKey" and use it to sign the assembly as shown

Now compile the solution and you will get the following errors

"Friend assembly reference "SimpleLibrary.Test" is invalid. Strong-name assemblies must specify a public key in their InternalVisibleTo declarations."
"Friend assembly reference "SimpleLibrary.Fakes" is invalid. Strong-name assemblies must specify a public key in their InternalVisibleTo declarations."

To resolve this, we need to sign our SimpleLibrary.Test assembly and change our InternalVisible attribute in the SimpleLibrary project to include the PublicKey as shown below


[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("SimpleLibrary.Test, PublicKey=00240000048000009400000006020000002400005253413100040000010001006bec6379ed95c6180028a6bc797cdb256805f6dcb61cbdf4f3f3493c5c25efb411fa33472565a5b5426161fd16a6a10802ae710f2e6828d175a2346e33f3831520bcf00e8584919cdf34ed11e51bb988f624360aeadf9b4dc764adc8aeab9939ad209b35f17f2d63192288b0e9bbe5ac013c56d7575b9277cde19e1be7d74f8b")]

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("SimpleLibrary.Fakes, PublicKey=00240000048000009400000006020000002400005253413100040000010001006bec6379ed95c6180028a6bc797cdb256805f6dcb61cbdf4f3f3493c5c25efb411fa33472565a5b5426161fd16a6a10802ae710f2e6828d175a2346e33f3831520bcf00e8584919cdf34ed11e51bb988f624360aeadf9b4dc764adc8aeab9939ad209b35f17f2d63192288b0e9bbe5ac013c56d7575b9277cde19e1be7d74f8b")]

Please note that by default the generated SimpleLibrary.Fakes.dll assembly will be signed with the same key as used in the original class. If we want, we can also use a different key to sign our fakes assembly. Recompile the project and we got errors similar to


"'SimpleClient' is inaccessible due to its protection level...."

The key step here is to include the KeyFile attribute in the Compilation element of the SimpleLibrary.Fakes file. The attribute will look like following, where Key file is the name of the key file used for signing the assembly

<Compilation KeyFile="SimpleLibraryKey.snk" />

Please note that the key file for the fakes assembly can be different from the original one. As long, as you are specifying the PublicKey of the key file specified in the Compilation attribute in the InternalVisible attribute, your code will compile and you can fake the internal classes.


Update 30/01/2013:

I have received some feedback and stand corrected on the key is used by Microsoft Fakes. The default key used by Fakes will always be the one shown below

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("SimpleLibrary.Fakes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e92decb949446f688ab9f6973436c535bf50acd1fd580495aae3f875aa4e4f663ca77908c63b7f0996977cb98fcfdb35e05aa2c842002703cad835473caac5ef14107e3a7fae01120a96558785f48319f66daabc862872b2c53f5ac11fa335c0165e202b4c011334c7bc8f4c4e570cf255190f4e3e2cbc9137ca57cb687947bc")]


My original understanding was that the key used by Micorosft Fakes is the same key that signs the assembly  it is faking. This is obviously not correct and this is mentioned clearly in MSDN http://msdn.microsoft.com/en-us/library/hh708916.aspx.  You can of course use a different key and and in that case the &ltCompilation KeyFile=""> would be required.

Saturday, 5 January 2013

Mocking HttpWebRequest using Microsoft Fakes

In my last post, I detailed the use of  RegisterPrefix method of the WebRequest class to mock calls to HttpWebRequest. I also mentioned that an alternative mechanism to isolate calls to HttpWebRequest was to use the Shims feature in Microsoft Fakes Framework. In this post, I will demonstrate how to do so.

Microsoft Fakes provides two ways of achieving isolation of "code under test" from underlying assemblies namely Stubs and Shims. The Stubs feature generates a dummy class implementing the interface to be stub'ed out allowing you to specify responses made to different method calls in your code. Shims, on the other hand, divert calls within the code of the underlying classes to the code you have written in your definition of the Shim. I wrote a post about Microsoft Fakes sometimes ago.

Coming back to the topic, below is a class that makes a call to the web service.

namespace FakesClass
{
    using System;
    using System.Net;
    /// <summary>
    /// Sample web service client class
    /// </summary>
    public class WebServiceClient
    {
        /// <summary>
        /// Calls a web service with the given URL
        /// </summary>
        /// <param name="url">The web service's URL</param>
        /// <returns>True if the services responds with an OK status code (200). False Otherwise</returns>
        public bool CallWebService(string url)
        {
            var request = CreateWebRequest(url);
            var isValid = true;
            try
            {
                var response = request.GetResponse() as HttpWebResponse;
                isValid = (HttpStatusCode.OK == response.StatusCode);
            }
            catch (Exception ex)
            {
                isValid = false;
            }
            return isValid;
        }

        /// <summary>
        /// Creates an HttpWebRequest object
        /// </summary>
        /// <param name="url">The URL to be called.</param>
        /// <returns>An HttpWebRequest.</returns>
        private static HttpWebRequest CreateWebRequest(string url)
        {
            var request = WebRequest.Create(url) as HttpWebRequest;
            request.ContentType = "text/xml;charset=\"utf-8\"";
            request.Method = "GET";
            request.Timeout = 1000;
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            return request;
        }
    }
}
The CallWebService method takes in the url string of the web service to be invoked and returns true or false depending upon whether the HttpResponse has a status code of 200 (HTTP OK) or not. This is a very simple example. You can get your response object to return a response string of whatever your unit test requirements is.

Now that we have a class to unit test, I created a unit test project adding a project reference to the project containing the WebServiceClient class.

Once the unit test project is created, the next step is to generate Fakes class for the HttpWebRequest, HttpWebResponse and WebRequest class. Since, these class reside in the System namespace, the way to generate fake class is to right click on the System Reference and click on the option "Add Fakes Assembly" as shown:


Please note that to date this option (and Microsoft Fakes) is only available for the Ultimate edition of Microsoft Visual Studio 2012.

The "Add Fakes Assembly" option will add the following two assemblies as reference in your unit test project
  • mscorlib.4.0.0.0.Fakes
  • System.4.0.0.0.Fakes
and also add a folder called "Fakes" with the following two files added to it
  • mscorlib.fakes
  • System.fakes




The reason that there are two set of files are added to the solution is because the System namespace is implemented in two assemblies. Since, we are faking only classes in System.Net namespace, we can safely remove the reference mscorlib.4.0.0.0.Fakes and the file mscorlib.fakes. The final references looks as follows
The .fakes file contain details of the files that would be shim'ed or stubbed in the tests. Since, we want to use shim for WebRequest, HttpWebRequest and HttpWebResponse, change the contents of the System.fakes file to the following text.

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
    <Assembly Name="System" Version="4.0.0.0"/>
    <StubGeneration>
        <Clear/>
    </StubGeneration>
    <ShimGeneration>
        <Clear/>
        <Add FullName="System.Net.WebRequest!"/>
        <Add FullName="System.Net.HttpWebRequest!"/>
        <Add FullName="System.Net.HttpWebResponse!"/>
    </ShimGeneration>
</Fakes>
As you can see, we have cleared out all stub generation and added the three desired classes in the <ShimGenerate\> section. Now, we are all ready to use the generated shims in our unit tests.

The name convention that Microsoft Fakes uses for stubs and shims is Stub{ClassName} & Shim{ClassName} respectively so our shim'ed classes HttpWebRequest class will be called ShimHttpWebRequest class and so on.  The following unit test demonstrates using the Shims.

[TestMethod]
public void TestThatServiceReturnsAForbiddenStatuscode()
{
    using (ShimsContext.Create())
    {
        // Arrange
        var requestShim = new ShimHttpWebRequest();
        ShimWebRequest.CreateString = (uri) => requestShim.Instance;
        requestShim.GetResponse = () => { return new ShimHttpWebResponse() { StatusCodeGet = () => { return HttpStatusCode.Forbidden; } }; };
        var client = new WebServiceClient();
        var url = "http://testwebservice.mywebservice.com";
        var expectedResult = false;
        //Act
        bool actualresult = client.CallWebService(url);
        //Assert
        Assert.AreEqual(expectedResult, actualresult);
    }
}
Please note that the test makes a call to ShimContext.Create and creates objects of type ShimWebRequest and ShimWebResponse. Also, the call to ShimWebRequest returns a ShimHttpWebRequest object.

Updated 23/01/2013: Here is the link to the visual studio solution used in this post and my previous post about mocking HttpWebRequest. The solution contains two unit test projects for testing the same class, one illustrating the use of RegisterPrefix method and the other using the Shim feature of Microsoft Fakes.
 

Thursday, 3 January 2013

Mocking HttpWebRequest

In one of my recent assignments, I had a requirement to call an external web service. As I wanted to isolate calls to the web service from the functionality that handles the response, I was looking to find ways of mocking calls to the web service. My first thoughts were to create an "IHttpRequest" interface and to encapsulate all HttpWebRequest through this interface.

However, since the call to create an HttpRequest requires casting a WebRequest into an HttpWebRequest, using interface to mock calls to HttpRequest wasn't particular. Following is a typical code block of creating HttpRequest (Note the typecast to HttpWebRequest)


        private static HttpWebRequest CreateWebRequest(string url)
        {
            var request = WebRequest.Create(url) as HttpWebRequest;
            request.ContentType = "text/xml;charset=\"utf-8\"";            
            request.Method = "GET";
            request.Timeout = 1000;
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            return request;
        }

Looking closely at the WebRequest class, I realised that the class is implementing the Factory Method pattern. To create your own factory class, all that is needed to be done is to create a class that implements the IWebRequestCreate interface and register this class to be used for the Urls in your web request calls. 

My testing requirements were to return different HttpStatusCodes, so my factory class looked as follows. Please note that I am using Moq for mocking.


    /// <summary>
    /// A custom implementation of IWebRequestCreate for Web Requests.
    /// </summary>
    /// <summary>A web request creator for unit testing.</summary>
    public class CustomWebRequestCreate : IWebRequestCreate
    {
        /// <summary>
        /// The web request.
        /// </summary>
        private static WebRequest nextRequest;

        /// <summary>
        /// Internally held lock object for multi-threading support.
        /// </summary>
        private static object lockObject = new object();

        /// <summary>
        /// Gets or sets the next request object.
        /// </summary>
        public static WebRequest NextRequest
        {
            get
            {
                return nextRequest;
            }

            set
            {
                lock (lockObject)
                {
                    nextRequest = value;
                }
            }
        }

        /// <summary>
        /// Creates the new instance of the CustomWebRequest.
        /// </summary>
        /// <param name="uri">The given Uri</param>
        /// <returns>An instantiated web request object requesting from the given Uri.</returns>
        public WebRequest Create(Uri uri)
        {
            return nextRequest;
        }

        /// <summary>
        /// Creates a Mock Http Web request
        /// </summary>
        /// <returns>The mocked HttpRequest object</returns>
        public static HttpWebRequest CreateMockHttpWebRequestWithGivenResponseCode(HttpStatusCode httpStatusCode)
        {
            var response = new Mock<HttpWebResponse>(MockBehavior.Loose);
            response.Setup(c => c.StatusCode).Returns(httpStatusCode);

            var request = new Mock<HttpWebRequest>();
            request.Setup(s => s.GetResponse()).Returns(response.Object);
            NextRequest = request.Object;
            return request.Object;
        }
    }

Having got this class, the setup code in my unit tests would look as follows

WebRequest.RegisterPrefix("http://testService.mywebservice.com", new CustomWebRequestCreate());

CustomWebRequestCreate.CreateMockHttpWebRequestWithGivenResponseCode(HttpStatusCode.OK);

Or

WebRequest.RegisterPrefix("http://testService.mywebservice.com", new CustomWebRequestCreate());            CustomWebRequestCreate.CreateMockHttpWebRequestWithGivenResponseCode(HttpStatusCode.Forbidden);

Just makes creating unit tests so much easier for a variety of response codes. You can extend the CustomWebRequest to mock your responses as you like.


Microsoft Fakes and .Net 4.5. 


The WebRequest class is extended in .Net 4.5 to include new CreateHttp(Uri) and CreateHttp(String) methods, each of which returns an HttpWebRequest object. So there is no need to have a cast. Also, the "Shims" functionality in Microsoft Fakes allows to describe the behaviour of .Net classes. So, HttpWebRequest.GetResponse() method can be "Shim'ed" out to return a response of your choice. This follow up post describes how to use fakes to isolate calls to HttpWebRequests.

Friday, 16 November 2012

Unit Tests using Microsoft Fakes framework in Team Build.


My last post was about Microsoft Fakes Framework. One thing to know about using Microsoft Fakes is that MSTest.exe does not support it. MSTest.exe used to be the executable that Visual Studio 2010 and earlier versions used to run unit tests. It is not the case anymore Visual Studio 2012 uses a command line tool vstest.console.exe. It resides in the %ProgramFiles%\Microsoft Visual Studio 11.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\ directory of your visual studio installation.

VSTest.console.exe provides most of the features of MSTest.exe  (there are a few alternatives), however, the version that was shipped with the initial release of Visual Studio, did not support publishing test results to TFS. This will change with Visual Studio 2012 Update 1, which is due to be released soon, but if you are a daredevil, you can try the Visual Studio CTP which is available for download now.

Also, if you are still using Team Foundation Server 2010, the default build template using MSTest activity, which uses MSTest.exe behind the scenes. This means that some of the unit tests which are working for you in Visual Studio environment might not work on the Team Build.

I am working on providing an activity in the Community TFS Build extension project to fill up this gap. For now, you can use InvokeProcess activity passing in all the command line parameters.

Wednesday, 7 November 2012

Microsoft Fakes Framework


If you have done any Test Driven Development than chances are that you have used one or more mocking frameworks. Mocking frameworks are great in that they isolate your code module from the layers underneath thus allowing you to execute your unit tests without elaborate test set up code. Also, they allow replicating different test scenarios. You can set up different responses from same calls to external components for different test scenarios.

With Visual Studio 2012, Microsoft has introduced a new Mocking framework called Fakes. To date, it is only available with the Ultimate edition of visual studio. The framework is comparable to other open source mocking frameworks such as RhinoMocks and Moq but has the following two advantages over others

  1. Great Integration with Visual Studio: The integration with Fakes with Visual Studio 2012 is brilliant. To create a "fake" of an assembly, a user needs to just right click on the references and click the option "Add Fake Assembly".


  1. Shims: Most mocking framework works by allowing developers to create a "Stub" of an object. Stubs are objects created on the fly, which implements the same interface as the original object. The caller controls the behaviour of the stub by specifying responses for the methods in the interface. Shims are different in that they "inject" code in the original assembly i.e. although the original object will be created but the code executed will the one specified in the shim. This is quite powerful in that it allows developers to specify behaviour of system assemblies, sealed classes and non-virtual methods. E.g. if you are writing some code that need to do something on the 1st day of a year and you are using System.Now, you can "Shim out" this System.Now to return first of January.

When you add a fakes assembly in your test project by right clicking on the reference assembly and clicking the "Add Fakes Assembly" option, visual studio adds the following files

  1. A new "Fakes" folder is created with a .fakes files created in it. For example, if you are creating fakes for "System.Configuration", a file called "System.Configuration.fakes" will be created. 

  1. A new "FakesAssemblies" folder is created with three files created namely originalAssembly.assemblyversion.Fakes.dlloriginalAssembly.assemblyversion.Fakes.xml and originalAssembly.assembly.Fakes.fakesconfig. So, for "System.Configuration" assembly the files generated would be System.Configuration.4.0.0.0.Fakes.dll, System.Configuration.4.0.0.0.Fakes.fakesconfig and System.Configuration.4.0.0.0.fakes.xml.

Visual Studio also adds a reference to the generated assembly in the "FakesAssemblies" folder.

The files in the "Fakes" folder are only generated at the time of adding the fakes assembly. They are added to the solution and should be checked into source control. 

The "FakesAssemblies" folder and all the files in it are generated whenever the project is compiled. This is important because if you are adding fakes for assembly for a changing component, the generation of FakesAssemblies will ensure that all changes are reflected in the generated assembly.

The purpose of this post is not to write details about Fakes and how to use it, but to mention about a "Gotcha" that you might stumble upon while working with it. I spent some time trying to fix that and wanted to write about it so that no one else gets burnt.

The issue was that one of the test projects using fakes was giving a compilation error when built by Team Build and failed with the following error

"Could not resolve this reference. Could not locate the assembly "System.Configuration.4.0.0.0.Fakes". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors."

The error would go away if I added the FakesAssemblies folder to TFS. This is not how it is meant to work. On closer examination, the reason this error happened was because the “Build action” for the .fakes file added to the project was not set correctly. These files should have the build action set to "Fakes". 










It was set to “None” 









and this is the reason why the fakesassemblies were not getting generated in the team build.