Share via


Setting Up the SharePoint Service Locator for Use in Unit Tests

Typical Goals

In this scenario, you want to run unit tests on isolated sections of code that use services from the service locator. To isolate the code, the service locator must return mock objects that you specify instead of the real implementation.

You can do this by replacing the current service locator instance with a service locator that you have created. It is also possible to create your own mock service locator that implements the IServiceLocator interface, but it is often easier to use the existing service locator such as the ActivatingServiceLocator class.

Solution

In Visual Studio, add a reference to the SharePoint Guidance Library, Microsoft.Practices.SPG.Common.dll, and to Microsoft.Practices.ServiceLocation.dll. Create an instance of the Microsoft.Practices.SPG.Common.ServiceLocation.ActivatingServiceLocator class and invoke its RegisterTypeMapping method. Use the interface and the implementation class you want your application class to use at run time as type parameters to the RegisterTypeMapping method. Call the ReplaceCurrentServiceLocator static method of the Microsoft.Practices.SPG.Common.ServiceLocation.SharePointServiceLocator class to set the current service locator.

Setting Up the SharePoint Service Locator for Use in Unit Tests

The following code shows a unit test's initialization method that replaces a configured service with a test-specific class. This example comes from the PricingFixture.cs class in the Contoso.LOB.Services.Tests project.

[TestClass()]
public class PricingFixture
{
   private MockSecurityHelper mockSecurityHelper;

   [TestInitialize]
   public void Init()
   {
       // Create the service locator that will be used by the tests.
       ActivatingServiceLocator serviceLocator = new ActivatingServiceLocator();

       // Populate it with a mock object for the ISecurityHelper. Instantiate it 
       // as a singleton, so each request to the service locator will return the 
       // same object.
       serviceLocator.RegisterTypeMapping<ISecurityHelper, 
                           MockSecurityHelper>(InstantiationType.AsSingleton);

       // Replace the SharePointServiceLocator's Current property with the one 
       // that was just created.
       SharePointServiceLocator.ReplaceCurrentServiceLocator(serviceLocator);

       // Get the mock object, so you can set some values on it in each unit test.
       this.mockSecurityHelper = 
          SharePointServiceLocator.Current.GetInstance<ISecurityHelper>() 
                                                          as MockSecurityHelper;
   }

   [TestMethod]
   public void GetPriceForUnknownPartnerReturnsBasePrice()
   {    
      // In the actual test, you can either set up your mocks to do what you want
      // or at the end of your tests, make sure they have been called.
      mockSecurityHelper.UserToReturn = "999";

      Pricing target = new Pricing();
      // ... Call some method on the Pricing object that needs
      // the mockSecurityHelper.
   }

   [TestCleanup]
   public void Cleanup()
   {
      // After each test, make sure to reset the ServiceLocator, to ensure you
      // do not interfere with other unit tests. 
      SharePointServiceLocator.Reset();
   }
}

Usage Notes

It is recommended that you use the Reset method to return the service locator to its original state as part of the unit test's cleanup step. This prevents tests from interfering with each other.

Passing the InstantiationType.AsSingleton enumerated value as an argument to the RegisterTypeMapping method allows you to specify that a single instance of the implementation class is used for all service location requests. This is important in the unit-testing scenario because you typically want to set test-specific properties of the mock object that your test environment provides. This technique allows the test environment to isolate the implementation under test. By default, the ActivatingServiceLocator class creates a new instance with each service location request.

Note

In the unit testing scenario, it is important to replace the current SharePoint service locator before you attempt to get the value of the SharePointServiceLocator.Current static property. The reason for this is that instantiating the default SharePoint service locator requires you to run in a SharePoint context, which may not be the case when performing a unit test. By replacing the current service locator before evaluating the SharePointServiceLocator.Current property, you can avoid a run-time dependency on the SharePoint environment.

Home page on MSDN | Community site