Click here to Skip to main content
15,867,756 members
Articles / Programming Languages / C#

How to Use Pex and Moles to Generate Unit Tests for a Project Having External Dependency (WCF Proxy) using Visual Studio 2010 SP1

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
24 Jan 2012CPOL3 min read 30.1K   14   4
Writing unit tests using Pex and Moles

In this post, I’ll discuss about writing unit tests using Pex and Moles. Pex and Moles are Visual Studio 2010 Power Tools that help Unit Testing .NET applications.

  • Pex automatically generates test suites with high code coverage. Right from the Visual Studio code editor, Pex finds interesting input-output values of your methods, which you can save as a small test suite with high code coverage.
  • Moles allows to replace any .NET method with a delegate. Moles support unit testing by providing isolation by way of detours and stubs, i.e., Generate a Mole type from the original type and redefine its behavior using delegates.

Pex and Moles can be downloaded from http://research.microsoft.com/en-us/projects/pex/.

I’ll explain the steps to generate unit tests for a project which calls a WCF service. Pex will be used to generate unit tests. Moles will be generated to isolate the external dependency (WCF proxy) and behavior will be redefined using delegates.

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 provided only a single operation.

C#
[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:

C#
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();
              }
        }
    }
}

Unit Testing DemoLibrary using Pex and Moles

In order to generate unit tests for WCF Service Client (DemoLibrary) project, the steps are:

  1. Right click on the class for which unit tests need to be generated and click “Create Parameterized Unit Tests” as displayed below:

    image

  2. A popup will be displayed where Filters and Output can be modified. Click Ok to go to the next step.

    image

  3. A new test project will be created. Test Class and Test stub will be added to this project as displayed below:
    C#
    /// <summary>This class contains parameterized unit tests for Search</summary>
    [PexClass(typeof(Search))]    [PexAllowedExceptionFromTypeUnderTest(typeof
    (InvalidOperationException))][PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), 
    AcceptExceptionSubtypes = true)]
    [TestClass]
    public partial class SearchTest
    {
         /// <summary>Test stub for GetResults(String)</summary>
         [PexMethod]
         public string GetResults([PexAssumeUnderTest]Search target, string s)
         {
             string result = target.GetResults1(s);
             return result;
             // TODO: add assertions to method SearchTest.GetResults(Search, String)
         }
    }
  4. There is an external dependency (GetResults makes a service call though the WCF Proxy) so “Run Pex Explorations” will not generate unit tests as displayed below:

    image

  5. In order to isolate the external dependency, we need to generate Moles before running Pex Explorations. Moles will be generated for DemoLibrary and System.ServiceModel assemblies and behavior will be redefined using delegates. There are two ways to generate a mole for an assembly. I’ll show you both the approaches:
    1. Visual Studio: This is the easiest way.
      1. Right click on the reference and generate Moles for that assembly as displayed below:image
      2. A .Moles file will be added to the project. Build the project and Moles.dll will be added to MolesAssemblies folder as displayed below:

        image

    2. Command Prompt: Moles can be generated from the command prompt.
      1. Run the moles.exe and specify the assembly path for which Moles needs to be created.

        image_thumb2[1]

      2. Copy the generated assembly to the Project and add reference to it.
  6. Similarly, as explained above, we need to generate Moles for System.ServiceModel assembly. For Visual Studio 2010 SP1, this may fail with error message “The type or namespace name 'IHttpCookieContainerManager' does not exist in the namespace 'ssm::System.ServiceModel.Channels' (are you missing an assembly reference?)”. This step however works fine for Visual Studio 2010. The fix is to exclude the type, i.e., 'IHttpCookieContainerManager' from StubGeneration as displayed below:

    image

  7. The next step is to Mock the Service call (redefine behavior using delegates) and add Asserts as displayed in code snippets below:
    C#
    /// <summary>Test stub for GetResults(String)
    [PexMethod]
    public string GetResults([PexAssumeUnderTest]Search target, string s)
    {
        MockWCFService<idemoservice>(); 
    
        MDemoServiceClient.Constructor = (var1) =>
           new MDemoServiceClient { }; 
    
        MDemoServiceClient.AllInstances.SearchString = (var1, var2) =>
        {
            return "Result";
        }; 
    
        string result = target.GetResults(s);
        PexAssert.IsNotNullOrEmpty(result);
        PexAssert.AreEqual(result, "Result");
        return result;            
    }
     
    /// <summary>
    /// Mocks the WCF service.
    /// </summary>
    private void MockWCFService<tservice>() where TService : class
    {
        MClientCredentials.Constructor = (var1) =>
            new MClientCredentials()
            {
                WindowsGet = () => { return new MWindowsClientCredential(); }
            }; 
    
        MClientCredentials.AllInstances.WindowsGet = (var1) =>
        {
            return new MWindowsClientCredential();
        }; 
    
        MWindowsClientCredential.AllInstances.ClientCredentialGet = (var1) =>
        {
            return new System.Net.NetworkCredential();
        }; 
    
        MWindowsClientCredential.AllInstances.ClientCredentialSetNetworkCredential = 
        (var1, var2) => { }; 
    
        MWindowsClientCredential.AllInstances.AllowNtlmGet = 
        (var1) => { return true; };
    
        MWindowsClientCredential.AllInstances.AllowNtlmSetBoolean = 
        (var1, var2) => { };
    
        MWindowsClientCredential.AllInstances.AllowedImpersonationLevelGet = 
        (var1) => { return System.Security.Principal.TokenImpersonationLevel.Impersonation; };
        MWindowsClientCredential.AllInstances.AllowedImpersonationLevelSetTokenImpersonationLevel = 
        (var1, var2) => { };
    
        MChannelFactory.AllInstances.CredentialsGet = 
        (var1) => { return new MClientCredentials(); };
    
        MClientBase<tservice>.AllInstances.ClientCredentialsGet = (var1) =>
        {
            return new System.ServiceModel.Description.ClientCredentials();
        }; 
    
        MClientBase<tservice>.AllInstances.ChannelFactoryGet = (var1) =>
        {
            return new MChannelFactory01<tservice>();
        }; 
    
        MClientBase<tservice>.AllInstances.StateGet = (var1) =>
        {
            return PexChoose.EnumValue<communicationstate>("CommunicationState");
        }; 
    
        MClientBase<tservice>.AllInstances.Close = (var1) =>
        { }; 
    
        MClientBase<tservice>.AllInstances.Abort = (var1) =>
        { };
    }
  8. Run Pex Explorations to generate unit tests for GetResults method as displayed below:

    image

  9. Unit tests will be added to the Test Class as displayed below:

    image

  10. Go to Test View and Run the unit tests as displayed below:

    image

Summary

In a similar way, we can extract out external dependencies using Moles and then run Pex Explorations. A few examples of external dependencies can be data layer, UI layer, server calls, etc. You can read more about Pex and Moles at http://research.microsoft.com/en-us/projects/pex/.

This article was originally posted at http://www.atulverma.com/feeds/posts/default

License

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


Written By
Software Developer (Senior)
India India
Atul works at Microsoft as a .NET consultant. As a consultant his job is to design, develop and deploy enterprise level secure and scalable solutions using Microsoft Technologies.

His technical expertise include .NET Framework(4.0, 3.5, 3.0), WPF, WCF, SharePoint 2010, ASP.net, AJAX, Web Services, Enterprise Applications, SQL Server 2008, Open Xml, MS Word Automation.

Follow him on twitter @verma_atul

He blogs at
http://www.atulverma.com
http://blogs.msdn.com/b/atverma

Comments and Discussions

 
GeneralCopy Pin
Member 841332427-Apr-12 4:04
Member 841332427-Apr-12 4:04 
GeneralRe: Copy Pin
atverma27-Apr-12 9:39
atverma27-Apr-12 9:39 
Well I had published the same on msdn too ...
1. Blog

2. Msdn Code sample

If there is some another msdn source let me know.

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.