Unit Testing with Service Stubs or Mock Types
Suppose your project also is using a distributed development model and the developers are learning LINQ and WCF, so the service is not ready even though you are ready to implement the service consumer. In this scenario, all you would need is an agreement on the definition of Customer and the service to be provided; that is, request a customer by ID and the service returns the right customer.
To insulate you from dependence on the service provider, you will need to implement a factory, an interface that describes the service's interface, a concrete type, and a mock type. Both the concrete and mock types have to realize—inherit from—the interface. The CustomerServicesFactory simply tries to return an instance of the concrete type, and if an exception occurs, it returns the mock type.
Listing 3 contains a console application that represents the client. I was bored, so the code actually uses a generic delegate to format the Customer—I was showboating a tad. All the code really does is request a Customer and send the customer state to the console.
Listing 3: A console application that sends the Customer state to the console—a little overkill using a generic delegate, but it was fun.
Imports UnitTestingWithMockTypes.ServiceReference1 Imports System.Runtime.CompilerServices Imports System.Reflection Imports System.Text Module Module1 Sub Main() Dim Format As Func(Of Customer, String) = _ Function(cust) (From prop In cust.GetType(). _ GetProperties()).Aggregate( _ New StringBuilder(), Function(builder, p) _ builder.AppendFormat("{0, -20}: {1}{2}", p.Name, _ p.GetValue(cust, Nothing), Environment.NewLine), _ Function(builder) builder.ToString()) Dim factory As ICustomerServices = _ CustomerServicesFactory.Create() Console.WriteLine(Format(factory.GetCustomer("ALFKI"))) Console.ReadLine() End Sub <Extension()> _ Function ToFormattedString(ByVal cust As Customer) Return (From prop _ In cust.GetType().GetProperties()).Aggregate( _ New StringBuilder(), Function(builder, p) _ builder.AppendFormat("{0}: {1}{2}", p.Name, _ p.GetValue(cust, Nothing), Environment.NewLine), _ Function (builder) builder.ToString()) End Function End Module
Listing 4 contains an implementation of the Factory pattern. Factory patterns exist to instantiate objects based on rules. In the example, the Factory defaults to the mock service object in the event of an exception. Listing 5 defines the interface that is part of mock typing (or the service stub enterprise pattern). Notice that the interface mirrors the WCF service.
Listing 4: Using an implementation of the Factory pattern to instantiate an instance of the concrete (or mock, as hardcoded to demonstrate) object as needed.
Public Class CustomerServicesFactory Public Shared Function Create() As ICustomerServices Try Throw New Exception Return New CustomerServices Catch ex As Exception Return New MockCustomerServices End Try End Function End Class
Listing 5: This interface is part of using mock types; declare the interface to instantiate a class that inherits from it.
Public Interface ICustomerServices Function GetCustomer(ByVal customerID As String) As Customer End Interface
Listing 6 implements the mock service with hard-coded Customer data, and Listing 7 actually consumes the service.
Listing 6: The mock class implements the interface but returns what is essentially test data.
Public Class MockCustomerServices Implements ICustomerServices Public Function GetCustomer(ByVal customerID As String) _ As Customer _ Implements ICustomerServices.GetCustomer Dim cust As Customer = New Customer cust.CustomerID = "ALFKI" cust.CompanyName = "Alfreds Futterkiste" cust.ContactName = "Paul Kimmel" cust.ContactTitle = "Sales Representative" cust.Address = "Obere Str. 57" cust.City = "Berlin" cust.Region = "" cust.PostalCode = "12209" cust.Country = "Germany" cust.Phone = "030-0074321" cust.Fax = "030-0076541" Return cust End Function End Class
Listing 7: Represents the concrete service wrapper, which actually interacts with the service.
Public Class CustomerServices Implements ICustomerServices Public Function GetCustomer(ByVal customerID As String) _ As Customer _ Implements ICustomerServices.GetCustomer Dim client As Service1Client = New Service1Client Return client.GetCustomer(customerID) End Function End Class
Page 3 of 4
This article was originally published on May 19, 2008