Web Service Tests

Finally, we get to the point of hooking the whole thing up and using the functionality that we built previously through the Web service. The first test we will write is to verify the id field, just as we did previously with the stub and database versions. We will need a Recording inserted into the database just as we did with the database tests. Here is the first test:

 [TestFixture] public class CatalogGatewayFixture : RecordingFixture {    private CatalogGateway gateway = new CatalogGateway();     private ServiceGateway.RecordingDto dto;     [SetUp]    public new void SetUp()    {       base.SetUp();       dto = gateway.FindByRecordingId(Recording.Id);    }    [Test]    public void Id()    {       Assert.AreEqual(Recording.Id, dto.id);    } } 

As you can see, the tests do follow a similar pattern. We retrieve a RecordingDto, in this case from a class named CatalogGateway , and verify that what was inserted into the database matches what is in the RecordingDto . Let s work on getting this to compile and run.

Web Service Producer and Consumer Infrastructure

Now, we need to address the question of how the test will access the Web service. We will use the Add Web Reference capability of Visual Studio .NET to generate the required code to handle the mechanics of consuming the Web service. But before we can create a Web reference, we need to define the Web service itself using WSDL. We will not author the WSDL by hand; we will once again rely on a tool to help us with the task.

We will use the WebMethod framework that comes as part of the ASP.NET Web services infrastructure. This framework allows generation of the required Web service WSDL by introspection of a class written in one of the .NET-supported languages. The framework defines a set of custom attributes that can be used to control the WSDL-generation process. Visual Studio .NET further simplifies the process of authoring a Web service by providing a Web service creation wizard that generates a template ASP.NET application to host the Web service. All we have to do is to define the code behind the page class that will implement the Web service s functionality.

Web Service Producer

We will name our Web service class CatalogServiceInterface . The wizard will generate the CatalogServiceInterface.aspx.cs template file, and we will add the FindByRecordingId WebMethod to this class:

 [WebService(Namespace="http://nunit.org/services", Name="CatalogGateway")] public class CatalogServiceInterface : System.Web.Services.WebService {    private DatabaseCatalogService service =        new DatabaseCatalogService();    public CatalogServiceInterface()    {       //CODEGEN: This call is required by the ASP.NET Web Services Designer       InitializeComponent();    }    [WebMethod]    public RecordingDto FindByRecordingId(long id)    {       return service.FindByRecordingId(id);    } } 

The CatalogServiceInterface class uses the DatabaseCatalogService that we built previously for retrieval and transformation.

Web Service Consumer

Now that we have defined the WebMethod interface, we can generate the required code to consume the Web service. We will add a Web reference to our project by selecting the URL of the Web service to locate the WSDL of the Web service. The Web Reference Wizard takes care of the rest and generates the CatalogGateway proxy class that our client code can use to consume the Web service. The generated proxy supports both a synchronous and an asynchronous service consumption model, but in this example, we use only the synchronous communication mode.

Also, you may notice that the Web Reference Wizard generated a different RecordingDto class that is used as the type of the return value of the FindByRecordingId WebMethod on the client side. This is expected because the Web service consumer and producer can be built on two different platforms, and the consumer may have a different type of system. The Add Web Reference Wizard used only the information available in our WSDL file to generate the required client-side type mappings, and because the RecordingDto is not a primitive type directly supported by the Simple Object Access Protocol (SOAP) serialization, we ended up with two RecordingDto types ”one on the server and one on the client. The Web services do not guarantee full type fidelity ”this is the price we have to pay for interoperability.

Running the Test

Now we are ready to run the CheckId test in the CatalogGatewayFixture . We get a failure because the Web service does not have the database access connection properly configured. We will need to add the connection settings to the Web.config file. We run it again and we still have a failure; this time, the Web service was denied access to the database because we have not defined the proper database login name for the Web service.

Web Services Security

Security is one of the most important aspects of building distributed systems. Security for Web services is a very large subject, and its treatment is beyond the scope of this book. There are several specifications in progress that address the issues of Web services security on the SOAP messaging level.

We will briefly touch on some of the security-integration aspects to the extent necessary to proceed with our work. We will consider the Web services security only as it is supported by the existing HTTP transport infrastructure. Because ASP.NET Web services are hosted as typical ASP.NET applications, the existing ASP.NET security infrastructure for authentication and authorization can be reused for Web services. We will need to decide how to manage the security context propagation from the ASP.NET tier to the ADO.NET tier of our application. We have a couple of options here:

  • Direct security context propagation by using trusted connections to the database Using this approach requires creating database login accounts for the ASP.NET user principals. If we support anonymous access to the ASP.NET application hosting our Web service, we will need to create an ASPNET account in the database server and grant this account the proper access rights to our catalog. If the ASP.NET application requires proper user authentication for access to the Web service, we may need to create several database accounts for each authenticated user principal. One of the main advantages of this approach is the fact that we can reuse existing database server security infrastructure to protect access to the data; however, this approach will also lead to the creation of individual connection pools for each user principal, and it does not scale well for a large number of users.

  • Mapped security contexts In this approach, we will have a single database login account for the entire Web service application. We can do either of the following:

    • Explicitly pass the user credentials to the database server for authentication (the username and password for this database login account will be stored in the Web.config file).

    • Map the caller principal on the ASP.NET service thread to the desired database login name and use the trusted connection to the database.

The mapped security context approach does not require creating a large number of connections (one for each distinct user principal).

We will be using the direct security context propagation approach and allow anonymous access to the Web service application to avoid creation of multiple database connections. Following this decision, we will need to add the ASP.NET user to the list of database login accounts and grant read/write rights for the catalog schema to this account. After making this change, we are ready to run our test again. Now it passes , and we are ready to move on and write the rest of the tests.

The tests for most of the fields were the same, but the tests TrackCount and ReviewCount were slightly different. In DatabaseCatalogService and in StubCatalogService , we could get the number of tracks or reviews by calling the Length method on the tracks and reviews fields, respectively. When we tried this on the Web service tests, we got a null reference exception. It turns out that if there are no tracks or reviews, the fields are not initialized as empty arrays ” they are left only as null values. So we had to change the tests on the CatalogGatewayFixture to the following:

 [Test]    public void TrackCount()    {       Assert.AreEqual(0, Recording.GetTracks().Length);       Assert.IsNull(dto.tracks);    }    [Test]    public void ReviewCount()    {       Assert.AreEqual(0, Recording.GetReviews().Length);       Assert.IsNull(dto.reviews);    } 

After we made these changes, we recompiled the code and reran all three sets of tests. They all pass, so we are done with the tests for the functionality. One last time we revisited the commonality of the CatalogGatewayFixture , DatabaseCatalogServiceFixture , and StubCatalogServiceFixture , and again we could not come up with anything that reduced the code duplication and increased the communication of what we were trying to do. So, this is one of those cases where there is code duplication but removing it reduces the communication.

Test-Driven Development in Microsoft .NET
Test-Driven Development in Microsoft .NET (Microsoft Professional)
ISBN: 0735619484
EAN: 2147483647
Year: 2004
Pages: 85

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net