Integration Testing WCF Services


In my previous post about unit testing WCF services, I hinted at the need to perform integration testing of services as well. As Jimmy writes, you should still place your logic involving OperationContext in the Service Interface Layer (SIL): In many cases, you need to know something about the context of the operation, such as authentication and authorization, and the SIL is the correct place to place this logic.


Let’s, for a moment, consider the need to perform authorization. You could inspect OperationContext.Current directly in each of your operation implementations, but that would be mixing concerns (business logic implemented in the operation mixed together with authorization). The correct way would be to provide a class deriving from ServiceAuthorizationManager, and configure the service to use this class for authorization. This would allow you to keep unit testing your operation implementations, but obviously, you also need to test the authorization manager itself, and it turns out that integration testing is the easiest way to accomplish this task.


To implement an authorization manager, you must override ServiceAuthorizationManager.CheckAccessCore or CheckAccess, which both take an instance of OperationContext as a parameter. If you could initialize a fully populated instance of OperationContext from a test, it would still be possible to unit test a custom authorization manager, but that turns out to be rather complex (OperationContext is a sealed class, so you can’t derive a stub from it; on the other hand, its sole constructor takes an instance of IContextChannel, so you could theoretically create a stub of IContextChannel, but that looks like more work than the alternative). For this reason, integration testing is the most efficient approach to testing a custom authorization manager, and indeed all code involving operation context in general (such as message interceptors, etc.).


In the rest of this post, I will show you how easy it is to create a basic integration test of a WCF service. For simplicity’s sake, I will start with a basic scenario where I only test the service operation itself. In future posts, I will address more advanced scenarios involving authentication and authorization.


As usual, the example service is stupidly simple:


public class MyService : IMyService
{
    #region IMyService Members
 
    public string DoStuff(string msg)
    {
        return msg;
    }
 
    #endregion
}

The integration tests should follow my principles for integration testing, which in this case are pretty easy to accomplish because WCF allows you to host a service in any managed process. Instead of having to set up a service by deploying it to, say, IIS and configuring the metabase, you can just host it directly in the test project.


Typically, I prefer setting up and starting the service only once per test suite, as starting a service takes a few seconds. As long as the service is stateless, starting the service once and having it handle all the requests from the individual test cases doesn’t violate the principle of test case independence, and it saves a lot of time:


[TestClass]
public class MyServiceTest
{
    private static ServiceHost myServiceHost_;
 
    [ClassInitialize]
    public static void InitializeClass(TestContext ctx)
    {
        MyServiceTest.myServiceHost_ =
            new ServiceHost(typeof(MyService));
        MyServiceTest.myServiceHost_.Open();
    }
 
    [ClassCleanup]
    public static void CleanupClass()
    {
        MyServiceTest.myServiceHost_.Close();
    }
}

In this case, I’m using the ClassInitialize and ClassCleanup attributes to start and stop the service corresponding to the lifetime of the test class. I could also have used AssemblyInitialize and AssemblyCleanup to host the same service instance for the entirety of the test library’s lifetime, but with services, I could imagine that one would sometimes prefer to be able to test the service with different deployment configurations, and by tying a service instance’s lifetime to a test class, one could create different test classes that each host their own service intance.


In the example shown above, the service is hosted using configuration from the application configuration file, so an app.config file containing the necessary configuration data must be added to the test project. Even so, at this point all we have is a running service, but no client.


There are several ways to create a proxy for the service. If you are using contract-first, you can use svcutil.exe to generate a proxy class from your wsdl file. On the other hand, if you rather prefer using the Add Service Reference feature of Visual Studio, you must first host the service, but how do you do that when the service is hosted in the same project where you want to add the proxy?


The first thing to know in this regard is that if you start up a project without debugging, you can still edit the project. Since this is a test project, you need to execute the test list (without debugging). At this point, you probably haven’t written any tests yet, but you need at least one (empty) test case to be able to run the test suite. Even so, you will probably not be able to add a service reference using the Visual Studio UI in the very short lifetime of the service instance. A simple hack to solve this problem is to temporarily insert a sleep statement after the service has started:


[ClassInitialize]
public static void InitializeClass(TestContext ctx)
{
    MyServiceTest.myServiceHost_ =
        new ServiceHost(typeof(MyService));
    MyServiceTest.myServiceHost_.Open();
 
    Thread.Sleep(TimeSpan.FromMinutes(1));
}

This gives you a minute in which you can add the service reference using the Visual Studio UI. When you have done this, remove the Thread.Sleep statement from InitializeClass again. You can now write a test case using the newly created proxy class:


[TestMethod]
public void InvokeServiceOperation()
{
    using (MyServiceClient proxy = new MyServiceClient())
    {
        string response = proxy.DoStuff(“Ploeh”);
 
        Assert.AreEqual<string>(“Ploeh”, response);
    }
}

In a future post, I will describe a more advanced WCF integration testing scenario.

Comments (28)

  1. For in-the-same-project-kinda-tests I often use the ChannelFactory generic which in its simplest form could be used in your example as:

    Binding b = new WSHttpBinding();

    ChannelFactory<IMyService> fact =

    new ChannelFactory<IMyService>(b,"http://localhost:8080/myservice&quot;);

    IMyService isrv = fact.CreateChannel();

    string a = isrv.DoStuff("test");

    Which will of course only work if the config file in your example specify a http binding with the address above.

    Good post! Look forward to reading the next one.

  2. I forgot to mention that the programmatic approach I showed above has the benefit that you don’t need to expose a metadata service endpoint that tools like svcutil.exe will be looking for.

  3. ploeh says:

    Hi Jimmy

    Thank you for your comments – good points, both, although whether svcutil will need a metadata endpoint depends on whether you generate a proxy from a live service, or a wsdl file. A metadata endpoint isn’t required in the latter case 🙂

    But I think I’ll try out your approach the next time around 🙂

  4. ploeh blog says:

    In my post about integration testing of WCF services , I hinted that one compelling reason to perform

  5. ploeh blog says:

    In my post about integration testing of WCF services , I briefly touched on the topic of authorization

  6. RajeshPR says:

    Hi

    Great article , was looking for some help on using NUnit with WCF.

    I will just briefly explain my scenario of what WCF is doing and then put across my queries related to NUint testing.

    My WCF Service does the basic work of performing DB CRUD operation say for example in the code snippet below it does the work of fetching list of employees and adding/updating new employee.

    The service and operation contract are defined as below

    [ServiceContract()]

    public interface IMyService

    {

    [OperationContract]

    EmpStructure[] GetEmployees();

    [OperationContract]

    string AddEmployee(EmpStructure dataContractValue);

    [OperationContract]

    string UpdateEmployee(EmpStructure dataContractValue);

    }

    My WCF Service class is defined as below and it implements the operation contract GetEmployees(), which returns a list of employees. This is for select operation

    public class MyService : IMyService

    {

    public EmpStructure[] GetEmployees()

    {

    EmpList response = new EmpList();

    ArrayList emps = new ArrayList();

    int i = 0;

    string EmployeeName="";

    SqlConnection cnn = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);

    SqlCommand cmd = new SqlCommand("SELECT * FROM emp" , cnn);

    cnn.Open();

    SqlDataReader reader = cmd.ExecuteReader();

    while (reader.Read())

    {

    EmpStructure Emp = new EmpStructure();

    Emp.EmpId =Convert.ToInt32(reader["EmpId"]);

    Emp.EmpName =(string)reader["Empname"];

    Emp.Basic =(decimal)reader["Basic"];

    emps.Add(Emp);

    i++;

    }

    reader.Close();

    cnn.Close();

    response.Employees = new EmpStructure;

    i=0;

    foreach (EmpStructure Employee in emps)

    {

    response.Employees = Employee;

    i++;

    }

    return response.Employees ;

    }

    }

    This operation defines Adding of a new employee

    public string AddEmployee(EmpStructure dataContractValue)

    {

    SqlConnection cnn = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);

    SqlCommand cmd = new SqlCommand("AddEmp", cnn);

    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add(new SqlParameter("@EmpName", SqlDbType.NVarChar, 50));

    cmd.Parameters.Add(new SqlParameter("@Basic", SqlDbType.Decimal));

    cmd.Parameters["@EmpName"].Value =dataContractValue.EmpName;

    cmd.Parameters["@Basic"].Value = dataContractValue.Basic;

    cnn.Open();

    cmd.ExecuteNonQuery();

    cnn.Close();

    return "Added Successfully" ;

    }

    This operation defines updating an employee information

    public string UpdateEmployee(EmpStructure dataContractValue)

    {

    SqlConnection cnn = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);

    SqlCommand cmd = new SqlCommand("UpdateEmp", cnn);

    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add(new SqlParameter("@EmpName", SqlDbType.NVarChar, 50));

    cmd.Parameters.Add(new SqlParameter("@Basic", SqlDbType.Decimal));

    cmd.Parameters.Add(new SqlParameter("@EmpID", SqlDbType.Int ));

    cmd.Parameters["@EmpName"].Value =dataContractValue.EmpName;

    cmd.Parameters["@Basic"].Value = dataContractValue.Basic;

    cmd.Parameters["@EmpId"].Value = dataContractValue.EmpId ;

    cnn.Open();

    cmd.ExecuteNonQuery();

    cnn.Close();

    return "Updated Successfully" ;

    }

    I also have an internal class which is basically used to enummerate through the list of employees and returns a collection of employee. This is represented using the EmpList class

    [Serializable]

    public class EmpList

    {

    private EmpStructure [] employees;

    public EmpStructure [] Employees

    {

    get { return employees; }

    set { employees = value; }

    }

    }

    Next I have a DataContract called EmpStructure which represents the values to be passed back n forth the service and which is actually a object representation for the Employee Table.

    [DataContract]

    public class EmpStructure

    {

    int empId;

    string empName;

    decimal basic;

    [DataMember]

    public int EmpId

    {

    get { return empId;}

    set { empId = value;}

    }

    [DataMember]

    public string EmpName

    {

    get { return empName;}

    set { empName = value;}

    }

    [DataMember]

    public decimal Basic

    {

    get { return basic;}

    set { basic = value;}

    }

    }

    Questions:

    1. How do I perform unit tests for the above DB related operations in WCF using NUint.

    2. Even if i decouple my service layer and data operation layer (into an class), how would I perform NUnit tests on the class.

    3. I tried creating a NUnit test scenario for the above service proxy, it looks like this

    code snippet:

    [TestFixture]

    public class TestClass

    {

    WCFTest.MyServiceClient testClient;

    WCFTest.EmpStructure[] empObj;

    [SetUp]

    public void Init()

    {

    testClient = new WCFTestClasses.WCFTest.MyServiceClient();

    }

    [Test]

    public void getEmp()

    {

    empObj = testClient.GetString();

    }

    }

    4. In the above case how will I perform my success and failure tests using Asserts….

    5. Is there any sample available which shows how to perform unit tests for CRUD operations using NUint.

  7. ploeh says:

    Hi Rajesh

    Thank you for writing. I think I can answer most of your questions, but before I go ahead and do that, we need to establish some common ground:

    What you are attempting to perform are not unit tests but integration tests. That doesn’t preclude the use of unit testing tools, but personally, I find the distinction important.

    Another thing is that most of my code samples and posts relate to the use of Visual Studio Team System unit tests, but you should be aware that all the techniques and principles I outline, apply equally well to NUnit, with only slight modifications.

    With that out of the way, I’ll attempt to answer your questions:

    1. There are two schools for integration testing of databases. In my post about Data Access Component Testing, I outline how I prefer to do it. In the MSDN Magazine article Know Thy Code: Simplify Data Layer Unit Testing using Enterprise Services, you can read about a different approach to data access testing.

    2. The normal way to decouple data access is to hide the data access component behind an interface or base class. You can then use some form of dependency injection to populate the service layer with an instance that implements the relevant interface. In a unit test, you would then create a stub or mock of that interface and inject that into your service class, thus completely removing the database from the equation.

    3 & 4. In this case, I don’t understand exactly what your MyServiceClient class does. Where does the GetString method come from? That operation is not part of the service contract, as far as I can see.

    If you want to validate, say, the GetEmployees method, you would need to call the GetEmployees method on the proxy and write the necessary Asserts against the return value.

    5. Please see my post about Data Access Component Testing for an outline of the principles.

    HTH

  8. Ravi says:

    Hi,

    How to use context in Nunit? With MS unit test framework the function with ClassInitialize attribute have TestContext parameter but in NUnit how context can be used?

    Thanks in advance.

    Ravi

  9. ploeh says:

    Hi Ravi

    Thank you for your question. It’s been a couple of years since I used NUnit, but as far as I remember, NUnit doesn’t have a test context. To validate, you can ask on an NUnit forum.

    For a lot of tests, the test context is never used (as is the case in this article). In VSTS, the test context can be used e.g. for data-driven tests, but I don’t think NUnit has this concept as well, which is probably the reason why no test context exists – at least, I never had any use for it when I used NUnit, and I still don’t need it today with VSTS.

  10. Ravi says:

    Thanks for your prompt reply 🙂

    I need to test methods of WCF service with NUnit.

    Actually, I have WCF service which contains use of OperationContext.Current from System.ServiceModel to retrieve some data like username. So how can pass the values to set OperationContext.Current from NUnit test method?

  11. ploeh says:

    Hi Ravi

    Thank you for clarifying your question. First of all: System.ServiceModel.OperationContext has nothing to do with Microsoft.VisualStudio.TestTools.UnitTesting.TestContext. In your case, that’s only a good thing, since NUnit’s lack of a test context doesn’t stop you from testing services that use OperationContext.Current.

    It’s pretty difficult to override OperationContext.Current from a unit test, but in theory, it should be possible, since this property is a static read/write property. This means that you can create a new instance of OperationContext in the beginning of your test, and then assign it to OperationContext.Current.

    It’s not particularly simple to do, though, since OperationContext is a sealed class, so you can’t stub it out. On the other hand, its single public constructor takes an instance of IContextChannel, so if you can stub that out, you should be good to go. However, this is quite a complext interface, so I’ve never really found it worthwhile to stub it out, but depending on your need, you might be able to get by that fairly easily be using a dynamic mock library.

    In any case, stubbing out OperationContext.Current is so difficult that I’ve personally never found it worth the while. That’s why I, when I need to test code that accesses OperationContext.Current, find it far easier to write an integration test as outlined in this post. If you want to do it with NUnit, all you need to do is to change the signature of the InitializeClass and CleanupClass methods to fit NUnit’s syntax.

    When you write an integration test as outlined here, WCF will automatically create and populate OperationContext.Current for you.

    HTH

  12. Ravi says:

    Hi,

    Thanks again,

    Yes, it is difficult to set OperationContext.Current from within the nunit method since we dont have available OperationContext.Current.

    As u responded that if I write an integration test as outlined here… I wrote intergration test to open service host and it worked fine but OperationContext.Current doesnt get populate.

    Thanks

  13. ploeh says:

    Hi Ravi

    OperationContext.Current should be automatically created by the WCF pipeline before your service method is invoked. On the other hand, it will only be available in the service operations, and not when you, for instance, initialize your service class.

    I’m not sure if I understand correctly what you are doing. Maybe you could share a simple repro?

  14. Ravi says:

    I have unit test class library project from where I used a method with[TestFixtureSetUp] attribute to initialize and run the service. In test method I called the service method which has OperationContext.Current to get username. Here I get null value for OperationContext.Current.

  15. ploeh says:

    Can you share a simple repro of this behavior? I can’t readily reproduce it.

  16. Ravi says:

    Here are unit test methods.

    [TestFixtureSetUp]

    public void MyClassInitialize()

    {

     try

     {

        Console.WriteLine("Class initialized");

        serviceHost = new ServiceHost(typeof(MyService));

        serviceHost.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(),

      "http://localhost/MyFirstService/MyService&quot;);

       serviceHost.Open();

       }

       catch (Exception ex)

       {

           Console.WriteLine(ex.Message);

           Assert.Fail(ex.Message);

       }

      }

    [TestMethod]

           public void GetUserDetails()

           {

               try

               {

                   Console.WriteLine("Start calling GetUserDetails function");

                  MyService myService = new MyService();

                  object userViewObject = myService.GetUserDetails("ravi");

                   Assert.IsNotNull(userViewObject, "Returned object can not be null");

                   Console.WriteLine("End calling GetUserDetails function");

               }

               catch (Exception ex)

               {

                   throw new Exception(ex.ToString());

               }

           }

    Here is part of service method.

    public UserView GetUserDetails(string userName)

    {

       try

       {

     string  loginName = null;

       foreach (ClaimSet claimSet in OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets)

       {

    foreach (Claim claim in claimSet)

    {

       if (claim.ClaimType == CsaClaimType.LoginName)

       {

    loginName = (string)claim.Resource;

       }    

    }

       }      

        }

        .

        .

        .

           }

    OperationContext.Current works fine in service method if it is called from console application and and page when used in it. It it is called from unit test method OperationContext.Current returns null.

  17. ploeh says:

    Hi Ravi

    Thank you for sharing your code. However, since this is not a complete implementation, I can’t reproduce your problem. Can you share a complete, simple repro of the problem?

  18. Pav says:

    Hello,

    I was wondering is it possible to call the WCF service by adding the dll into the Test Project and maintain the Thread.CurrentPrinciple? Reason i ask is because i am testing a WCF Service and i want to bypass the proxy and call the service dll which has been referenced in my test project. I can successfully start debugging into the WCF service but i get an error when trying to assign the Thread.Principle.Name which is Null.

    Thanks,

    Pav

  19. ploeh says:

    Hi Pav

    Thanks for writing.

    You can indeed unit test WCF services, as described in this post: http://blogs.msdn.com/ploeh/archive/2006/12/03/UnitTestingWCFServices.aspx.

    This effectively bypasses all WCF infrastructure, so you will need to manually populate Thread.CurrentPrincipal as part of your Fixture Setup. I’ve done that many times, and it works very well.

  20. Pav says:

    Hi Ploeh,

    Thanks for your response

    Ahh of course in the Test Initialise Setup/Teardown, that makes sense!! I somehow thought the Current Thread was seperate in the two dll’s and hence the CurrentPrinciple would not be persisted (duh!)

    Pav

  21. ploeh says:

    Hi Pav

    Good to hear that you were able to address your issue – I’m always happy to be able to help 🙂

  22. As you may know, testing WCF services is not as simple as referencing a service implementation and start

  23. Dave says:

    What is the best way to unit test WCF services when you have callbacks?

  24. ploeh says:

    Hi Dave

    Thank you for your question. Since I thought it was of general interest, I wrote a post about it: http://blogs.msdn.com/ploeh/archive/2008/06/28/unit-testing-duplex-wcf-services.aspx

    HTH

  25. Jeremy says:

    This was an extremely helpful and concise post.

    Thanks much,

    Jeremy

  26. ploeh blog says:

    ADO.NET Data Services enables you to expose data (including, but not limited to, relational data) as

  27. hari says:

    can any one tel me the sample code for nuit implementation in wcf service