Unit Test a project having external dependency(WCF Proxy) using Fakes & Visual Studio 11 Beta

In this post I’ll explain the steps to generate unit tests for a project which calls a WCF service using Fakes. Microsoft Fakes is an isolation framework for creating delegate-based test stubs and shims in .NET Framework applications. The Fakes framework can be used to shim any .NET method, including non-virtual and static methods in sealed types.

The Fakes framework helps developers create, maintain, and inject dummy implementations in their unit tests. The Fakes framework generates and maintains stub types and shim types for a system under test.

I had previously discussed about creating Unit Tests using Pex, Moles and Visual Studio 2010. The projects inside the sample solution are

  1. DemoService: This project is a WCF Service.
  2. DemoLibrary: This project is a Class library and service reference to DemoService has been added. Unit tests will be generated for this project.
  3. ConsoleApp: This project is a Console application.
  4. DemoLibrary.Tests: This is a Test project and contains unit tests for DemoLibrary.

The solution structure is displayed below

image

DemoLibrary calls DemoService though proxy as displayed in the Layer diagram

image

I’ll now discuss in brief the code snippets of each project

WCF Service(DemoService): This service provides only a single operation

 [ServiceContract]
 public interface IDemoService
 {
     [OperationContract]
     string Search(string criteria);
 }
  

WCF Service Client(DemoLibrary): It calls the Search method of DemoService through proxy as displayed below

 public string GetResults(string s)
 {
     DemoServiceReference.DemoServiceClient client = null;
  
     try
     {
         client = new DemoServiceReference.DemoServiceClient();
         client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;                
         client.ChannelFactory.Credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
         s = client.Search(s);
         return s;
     }
     finally
     {
         if (client != null)
         {
             if (client.State == CommunicationState.Opened)
             {
                 client.Close();
             }
             else if (client.State == CommunicationState.Faulted)
             {
                 client.Abort();
             }
         }
     }
 }
  

Adding Unit Tests for DemoLibrary:

In order to Unit Test WCF Service Client(DemoLibrary) project using Fakes and Visual Studio 11 the steps are

  1. Add a new Unit Test project as displayed below

    image

  2. In order to isolate the dependencies we need to add Fakes for DemoLibrary and System.ServiceModel assemblies and behaviour will be redefined using delegates. Add Fakes assembly as displayed below

    image

  3. A .fakes file will be added to the project under Fakes folder and reference to {Assembly}.Fakes.dll will be added as displayed below 

    image

  4. Similarly as explained above we need to generate Fakes for System.ServiceModel assembly. I got “Failed to generate Stub/Shim for type …” error messages on building the project. There are couple of ways to fix it.

    1. Change the Target Framework of the Test project from .NET Framework 4.5 to .NET Framework 4.0

    2. Open the System.ServiceModel.fakes and remove the types for which Shim/Stub generation is failing. Since I’m not using Stubs I’ve disabled the StubGeneration as displayed below

      image

  5. The next step is to Mock the Service call(redefine behaviour using delegates) and add Asserts as displayed in code snippets below. The main points are

    1. I have used Shims to isolate calls to non-virtual functions in unit test methods. Read more about Shim and Stub types.
    2. When using shim types in a unit test framework, you must wrap the test code in a ShimsContext to control the lifetime of your shims.
     [TestMethod]
     public void TestSearch()
     {
         using (ShimsContext.Create())
         {
             ShimWCFService<IDemoService>();
      
             ShimDemoServiceClient.Constructor = (var1) =>
             {
                 new ShimDemoServiceClient { };
             };
    
             ShimDemoServiceClient.AllInstances.SearchString = (var1, var2) =>
             {
                 return "Result";
             };
    
             Search search = new Search();
             string result = search.GetResults("test");
             Assert.IsNotNull(result);
             Assert.AreEqual(result, "Result");
         }
     }
      
     /// <summary>
     /// Mocks the WCF service.
     /// </summary>
     private void ShimWCFService<TService>() where TService : class
     {            
         ShimClientCredentials.Constructor = (var1) =>
         {
             new ShimClientCredentials();
         };
      
         ShimClientCredentials.AllInstances.WindowsGet = (var1) =>
         {
             return new ShimWindowsClientCredential();
         };
      
         ShimWindowsClientCredential.AllInstances.ClientCredentialGet = (var1) =>
         {
             return new System.Net.NetworkCredential();
         };
      
         ShimWindowsClientCredential.AllInstances.ClientCredentialSetNetworkCredential = (var1, var2) => { };
      
         ShimWindowsClientCredential.AllInstances.AllowNtlmGet = (var1) => { return true; };
      
         ShimWindowsClientCredential.AllInstances.AllowNtlmSetBoolean = (var1, var2) => { };
      
         ShimWindowsClientCredential.AllInstances.AllowedImpersonationLevelGet = (var1) => { return System.Security.Principal.TokenImpersonationLevel.Impersonation; };
      
         ShimWindowsClientCredential.AllInstances.AllowedImpersonationLevelSetTokenImpersonationLevel = (var1, var2) => { };
      
         ShimChannelFactory.AllInstances.CredentialsGet = (var1) =>
         { return new ShimClientCredentials(); };
      
         ShimClientBase<TService>.AllInstances.ClientCredentialsGet = (var1) =>
         {
             return new System.ServiceModel.Description.ClientCredentials();
         };
      
         ShimClientBase<TService>.AllInstances.ChannelFactoryGet = (var1) =>
         {
             return new ShimChannelFactory<TService>();
         };
      
         ShimClientBase<TService>.AllInstances.StateGet = (var1) =>
         {
             return CommunicationState.Opened;
         };
      
         ShimClientBase<TService>.AllInstances.Close = (var1) =>
         { };
      
         ShimClientBase<TService>.AllInstances.Abort = (var1) =>
         { };
     }
    
  6. Go to Unit Test explorer and run the tests

    image

  7. You can also Analyze the code coverage. The code coverage results are displayed below

    image

 

The sample is available for download @ Download Source code