This post is for refining my previous post Test WCF web service – Hosted in ASP.NET Development Server. Personally, I prefer Wordpress because it is easy to maintain layout. But all blogs at wordpress.com are censored by the Great Firewall of China (I always want to say the word that has 4 characters, starts with “F” and ends with “K” when talking about it). So I decided to continue to blog in BlogSpot.
I started working in Microsoft Shanghai Global Technical Support Center on May 5th 2008. Fortunately, the company has a private line connecting to the USA thus we can bypass the Great Firewall in the office. My friends and I have dreamed this all our lives. When I wrote the previous post about testing WCF web service, I just had several weeks of experience in VSTT, so forgive me for not having made it easy to read. Since published that post, I have received many feedbacks, thank you all! It’s time to refine the post.
I remember last year the MSDN document at http://msdn.microsoft.com/en-us/library/ms243399.aspx was the same as that in http://msdn.microsoft.com/en-us/library/ms243399(VS.80).aspx. Then Microsoft has changed the terminology about unit test. It is said that hosting a web service and actually invoking it over HTTP in a test method is considered to be “integration test”, while creating an instance of the web service class in a test method and invoking it’s methods is the “unit test”. So I guess the topic of this post is about how to host WCF web services and perform integration testing.
I focus on testing WCF web services that are hosted in ASP.NET Deployment Server (Cassini).
Background about ASP.NET unit testing.
Let me explain some background about ASP.NET unit testing. ASP.NET unit tests can (not always) be executed in the same process as the web server. See Overview of ASP.NET Unit Tests for more information. At run time of executing ASP.NET unit tests, it goes through the following steps:
- Backup your web.config to web.config.backup.
- Register an HTTP module Microsoft.VisualStudio.TestTools.HostAdapter.Web.HttpModule, which is in %Program Files%\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.QualityTools.HostAdapters.ASPNETAdapter. to the web.config.
- Start ASP.NET Deployment Server if it is used.
- Send a request to the URL pointed by UrlToTest attribute of your test method.
- The registered Microsoft.VisualStudio.TestTools.HostAdapter.Web.HttpModule is triggered by the web server. The module subscribes the PageLoad event of the requested page. When PageLoad event is fired, it loads the test assembly in to the web server process and execute the test method.
- Restore the web.config and delete web.config.backup after tests complete.
ASP.NET Deployment Server is started when running a unit test if one of the following 2 conditions is meet:
- AspNetDeploymentServer attribute is specified.
This attributes tells VS to start Cassini before executing the test method. Both AspNetDeploymentServer and AspNetDeploymentServerHost expects a physical path to the web application. In a team environment, the web site is usually located in different directories in different computers. The workaround is to use environment variables. See Testing Web Sites and Web Services in a Team Environment for more information. - UrlToTest and HostType and AspNetDeploymentServerHost attributes are all specified.
UrlToTest attribute is required if HostType attribute is set to “ASP.NET”. The combination of the 3 attributes let VS know ASP.NET Deployment Server should be started and the test method should be executed in the same process as the web server.
When testing web services, we usually want to invoke the web services from a proxy and it’s not necessary to execute test methods in the same process as the web server. Therefore, we don’t need to UrlToTest, HostType and AspNetDeploymentServerHost attributes.
Testing WCF web services hosted in ASP.NET Deployment Server
I go through the process of creating a WCF project and add a test method to demonstrate this scenario. Several sentences here are copied from http://msdn.microsoft.com/en-us/library/ms243399(VS.80).aspx.
- Create a WCF project in VS via File->New->Project->Visual C#->Web->WCF Service Application.
- Generate unit tests against the Web service in the standard way for generating unit tests. For more information, see How to: Generate a Unit Test.
- Use svcutil to generate WCF web service proxy.
- Right click the Service1.svc in the WCF project in Solution Explorer and select View in Browser.
- Run svcutil http://localhost:52747/Service1.svc /config:app.config /out:Service1Proxy.cs /language:C# to generate proxy and config file. Please replace the URL of Service1.svc to that was displayed in the address bar of the browser in #1.
- Add Service1Proxy.cs and app.config to the test project.
- Remove the attribute HostType, UrlToTest and AspNetDeploymentServerHost for the generated test method.
- Add the AspNetDevelopmentServerAttribute attribute to the unit test. The arguments for this attribute class point to the site of the Web service and name the server. For more information, see Ensuring Access to ASP.NET Development Server.
- Change the test method to use the generated proxy class to invoke the web service and add the redirection logic. The test class will look like the following.
I also paste some code here to ease reverences.
WcfWebServiceHelper.cs
using System;
using System.Reflection;
using System.ServiceModel.Description;
using System.ServiceModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
class WcfWebServiceHelper
{
public static bool TryUrlRedirection(object client, TestContext context, string identifier)
{
bool result = true;
try
{
PropertyInfo property = client.GetType().GetProperty("Endpoint");
string webServer = context.Properties[
string.Format("AspNetDevelopmentServer.{0}", identifier)].ToString();
Uri webServerUri = new Uri(webServer);
ServiceEndpoint endpoint = (ServiceEndpoint)property.GetValue(client, null);
EndpointAddressBuilder builder = new EndpointAddressBuilder(endpoint.Address);
builder.Uri = new Uri(
endpoint.Address.Uri.OriginalString.Replace(
endpoint.Address.Uri.Authority, webServerUri.Authority));
endpoint.Address = builder.ToEndpointAddress();
}
catch (Exception e)
{
context.WriteLine(e.Message);
result = false;
}
return result;
}
}
}
Test Method
[TestMethod()]
[AspNetDevelopmentServer("WcfService1",
"C:\\Users\\Administrator\\Desktop\\TfsRoot\\BuildTest\\Main\\MyServices\\WcfService1")]
public void GetDataTest()
{
Service1Client target = new Service1Client();
Assert.IsTrue(WcfWebServiceHelper.TryUrlRedirection(target,TestContext,"WcfService1"));
int value = 0;
string expected = "You entered: 0";
string actual;
actual = target.GetData(value);
Assert.AreEqual(expected, actual);
}