Welcome to MSDN Blogs Sign in | Join | Help

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.

Published Monday, December 04, 2006 8:42 PM by ploeh
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# ploeh blog : Unit Testing WCF Services

Monday, December 04, 2006 2:45 PM by ploeh blog : Unit Testing WCF Services

# re: Integration Testing WCF Services

Monday, December 04, 2006 4:14 PM by jimmytr

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");

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.

# re: Integration Testing WCF Services

Monday, December 04, 2006 4:22 PM by jimmytr

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.

# re: Integration Testing WCF Services

Tuesday, December 05, 2006 4:28 AM by ploeh

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 :)

# Integration Testing With Certificates

Wednesday, December 20, 2006 4:13 PM by ploeh blog

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

# Mapping SAML Tokens to IPrincipals

Thursday, January 04, 2007 1:49 PM by ploeh blog

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

# re: Integration Testing WCF Services

Wednesday, February 07, 2007 12:17 AM by RajeshPR

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.

# re: Integration Testing WCF Services

Wednesday, February 07, 2007 4:47 AM by ploeh

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

# re: Integration Testing WCF Services

Monday, March 12, 2007 8:18 AM by Ravi

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

# re: Integration Testing WCF Services

Monday, March 12, 2007 8:32 AM by ploeh

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.

# re: Integration Testing WCF Services

Monday, March 12, 2007 8:56 AM by Ravi

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?

# re: Integration Testing WCF Services

Monday, March 12, 2007 9:17 AM by ploeh

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

# re: Integration Testing WCF Services

Tuesday, March 13, 2007 7:48 AM by Ravi

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

# re: Integration Testing WCF Services

Tuesday, March 13, 2007 7:59 AM by ploeh

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?

# re: Integration Testing WCF Services

Tuesday, March 13, 2007 9:54 AM by Ravi

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.

# re: Integration Testing WCF Services

Tuesday, March 13, 2007 12:26 PM by ploeh

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

# re: Integration Testing WCF Services

Wednesday, March 14, 2007 1:38 AM by Ravi

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");

   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.

# re: Integration Testing WCF Services

Thursday, March 15, 2007 9:32 AM by ploeh

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?

# re: Integration Testing WCF Services

Friday, January 11, 2008 11:42 AM by Pav

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

# re: Integration Testing WCF Services

Friday, January 11, 2008 11:57 PM by ploeh

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.

# re: Integration Testing WCF Services

Wednesday, January 16, 2008 11:20 AM by Pav

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

# re: Integration Testing WCF Services

Wednesday, January 16, 2008 9:14 PM by ploeh

Hi Pav

Good to hear that you were able to address your issue - I'm always happy to be able to help :)

# Unit tests for WCF (And Moq)

Friday, May 16, 2008 11:15 AM by Pablo M. Cibraro (aka Cibrax)

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

# re: Integration Testing WCF Services

Monday, June 23, 2008 3:55 PM by Dave

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

# re: Integration Testing WCF Services

Saturday, June 28, 2008 8:51 AM by ploeh

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

# re: Integration Testing WCF Services

Tuesday, November 11, 2008 5:11 PM by Jeremy

This was an extremely helpful and concise post.

Thanks much,

Jeremy

# Unit Testing ADO.NET Data Services

Tuesday, January 13, 2009 7:05 AM by ploeh blog

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

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker