User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

    Unit Testing with Service Stubs or Mock Types



    Introduction

    The simple fact of life is that ideas overlap and sometimes are attributed to multiple sources. For instance, I grew learning that Marconi invented radio. Turns out that Tesla invented the radio and now holds the patent posthumously.

    An overlapping idea that I believe—but don't quote me—came out of Agile software development is the concept of mock types. In the patterns world "mock types" are called "service stubs." Who invented the idea is important to that person, but the concept of whether we call it mock type or service stub is important to us.

    The basic idea is that many of us are building distributed applications with essential third-party services, and sometimes those third-party services are unavailable. Mock types (or service stubs; I will use mock types for the rest of this article) represent a strategy for handling critical services, fostering forward momentum even when those services may be temporarily disrupted.

    For example, I worked on a project recently that interacted with AAMVA—the American Association of Motor Vehicle Administrators. AAMVA is an external resource that was critical to our application. In our environment, AAMVA only provided an e connection. This meant that if multiple developers were working on AAMVA, they either had to coordinate their time on AAMVA, or if AAMVA was unavailable no one could test their AAMVA code.

    The basic idea is that if you have critical services in your applications topology, you can and should build mock types for when those services are disrupted for whatever reason. For your purposes, a service can be anything that is external to any consuming code. Web services, third-party providers, the difference between your client layer and business layer. Roughly anything that might be unavailable during development and unit testing can use the mock type strategy.

    Conceptualizing Mock Types

    For your purposes, simplify the concept of a service to a provider—some code that provides some capability—that is non-trivial or if trivial, supplied by a distributed, remote, or third party. Many times, the first step taken is to code write to the interface of the provider and connect that to some part of your application. Mock types add a level of abstraction, an interface. The interface contract is the capabilities of the provider—functions and properties.

    The next step is to implement a class that is the concrete provider at some point. The mock type is represented by a concrete provider that simply satisfies the contract of the interface. The easiest way to implement a mock type is to define a class, realize the interface, and return hard-coded values. Remember that a mock type is a stub that exists to simulate, or mock up, the capabilities of the provider so that you can code or test the consumer. (The consumer being your code that will ultimately use the provider.

    Tip: The key concept for mock type strategies is that interdependent parts of your application come together at different times. If consumer A is dependent on provider B and B isn't ready, a stub for provider B permits A's development to proceed.

    In your consumer, declare an instance of the interface and then initialize an instance of the actual provider you want. If you use a factory class to return the provider instance, you can add additional information—for example, to your App.config file—that determines when to return the mock type and when to return the concrete type. Figure 1 shows a simple class diagram that illustrates the mock type relationships.

    Figure 1: Use a stubbed out class that returns simple data or hard-coded data as a place holder for an actual piece of code that may be unavailable at times.

    Implementing Mock Types

    Some of you may not read UML. Some of you, so UML diagrams and written explanations are usually balanced nicely with code. In the example for this article, there is a service called NorthwindService implemented in WCF. The service returns a customer based on a CustomerID. Underneath the service is LINQ to SQL code that does the database work and the WCF service contract uses a LINQ query to extract just the customer desired and returns that Customer object.

    Tip: For the demo I used SQL Server 2005, the Northwind database, and LINQ to SQL all with Visual Studio 2008, .NET 3.5, and VB9.

    The WCF service implementation is shown in Listing 1. Listing 2 provides the ServiceContract, the DataContext, and the ORM (object relational mapping) mapped table. The ServiceContract is part of WCF. The DataContext is part of LINQ to SQL, and the ORM table-mapped class is also part of LINQ to SQL.

    Listing 1: The WCF service implementation based on the contract in Listing 2 requests a list of customers with LINQ to SQL and refines the list based on a LINQ query (shown).

    ' NOTE: If you change the class name "Service1" here, you must
    ' also update the reference to "Service1" in Web.config and in
    ' the associated .svc file.
    Public Class Service1
       Implements IService1
    
       Public Sub New()
       End Sub
    
       Public Function GetCustomer(ByVal CustomerID As String) _
          As Customer _
          Implements IService1.GetCustomer
    
          Dim northwind As Northwind = New Northwind
    
          Dim cust = (From customer In northwind.Customers _
                      Where customer.CustomerID = CustomerID _
                      Select customer).First()
          Return cust
    
       End Function
    End Class
    

    Listing 2: Defines the ServiceContract, the custom DataContext (for LINQ to SQL), and the table-mapped ORM (the Customer class).

    Imports System.Data.Linq
    Imports System.Data.Linq.Mapping
    
    <ServiceContract()> _
    Public Interface IService1
    
       <OperationContract()> _
       Function GetCustomer(ByVal CustomerID As String) As Customer
    
    End Interface
    
    Public Class Northwind
       Inherits DataContext
    
       Private Shared ReadOnly connectionString As String
    
       Public Sub New()
          MyBase.New(connectionString)
       End Sub
    
       Public ReadOnly Property Customers() As List(Of Customer)
          Get
             Return Me.GetTable(Of Customer)().ToList()
          End Get
       End Property
    
    End Class
    
    <DataContract()> _
    <Table(Name:="Customers")> _
    Public Class Customer
    
       Private _customerID As String
       <DataMember()> _
       <Column(IsPrimaryKey:=True)> _
       Public Property CustomerID() As String
          Get
             Return _customerID
          End Get
          Set(ByVal Value As String)
             _customerID = Value
          End Set
       End Property
    
       Private _companyName As String
       <DataMember()> _
       <Column()> _
       Public Property CompanyName() As String
          Get
             Return _companyName
          End Get
          Set(ByVal Value As String)
             _companyName = Value
          End Set
       End Property
    
       Private _contactName As String
       <DataMember()> _
       <Column()> _
       Public Property ContactName() As String
          Get
             Return _contactName
          End Get
          Set(ByVal Value As String)
             _contactName = Value
          End Set
       End Property
    
       Private _contactTitle As String
       <DataMember()> _
       <Column()> _
       Public Property ContactTitle() As String
          Get
             Return _contactTitle
          End Get
          Set(ByVal Value As String)
             _contactTitle = Value
          End Set
       End Property
    
       Private _address As String
       <DataMember()> _
       <Column()> _
       Public Property Address() As String
          Get
             Return _address
          End Get
          Set(ByVal Value As String)
             _address = Value
          End Set
       End Property
    
       Private _city As String
       <DataMember()> _
       <Column()> _
       Public Property City() As String
          Get
             Return _city
          End Get
          Set(ByVal Value As String)
             _city = Value
          End Set
       End Property
    
       Private _region As String
       <DataMember()> _
       <Column()> _
       Public Property Region() As String
          Get
             Return _region
          End Get
          Set(ByVal Value As String)
             _region = Value
          End Set
       End Property
    
       Private _postalCode As String
       <DataMember()> _
       <Column()> _
       Public Property PostalCode() As String
          Get
             Return _postalCode
          End Get
          Set(ByVal Value As String)
             _postalCode = Value
          End Set
       End Property
    
       Private _country As String
       <DataMember()> _
       <Column()> _
       Public Property Country() As String
          Get
             Return _country
          End Get
          Set(ByVal Value As String)
             _country = Value
          End Set
       EndProperty
    
       Private _phone As String
       <DataMember()> _
       <Column()> _
       Public Property Phone() As String
          Get
             Return _phone
          End Get
          Set(ByVal Value As String)
             _phone = Value
          End Set
       End Property
    
       Private _fax As String
       <DataMember()> _
       <Column()> _
       Public Property Fax() As String
          Get
             Return _fax
          End Get
          Set(ByVal Value As String)
             _fax = Value
          End Set
       End Property
    
    End Class
    

    IT Offers


    Top Authors