Freigeben über


Faking The Windows Azure Table Service

When presented with a new technology, one of my primary evaluation criteria is its testability, so it should come as no surprise to the regular reader of this blog that this was also foremost in my mind when Windows Azure was presented at PDC. Much of the Azure Services Platform is just .NET, so testability is really up to you, just like with all other .NET code.

However, when it comes to the Windows Azure storage, the developer story is different. The Windows Azure Table Service is essentially a REST-based service, and to use it, you'll need to install the Azure Visual Studio SDK.

That's not a problem in itself, but it seems to be implemented as a REST service on top of SQL Server Express. While that may be good enough for casual development, that's quite heavyweight for unit testing. Imagine having to somehow deal with populating and cleaning this database between each test case. That will likely involve a fair amount of complex and undocumented Back Door Manipulation. As the service is out of process in relation to the test, this is brittle and slow, so a better approach is warranted.

Fortunately, I've already demonstrated how to Fake a REST-based Data Service, so faking the Windows Azure Table Service turns out to be fairly easy, and generally follows the same steps as previously outlined.

In the following example, I'm working with a simple service that echoes messages back to the caller. The Delay method saves the input message in table storage and returns the previous message from storage. This test verifies that the input message is being correctly saved:

 [TestMethod]
 public void DelayWillSaveMessage()
 {
     // Fixture setup
     string expectedMessage = "Anonymous text";
  
     Uri address = new Uri("https://localhost/EchoService");
     FakeDataService<MessageContainer> service = 
         new FakeDataService<MessageContainer>(
             new MessageContainer());
     using (WebServiceHost host = 
         new WebServiceHost(service, new[] { address }))
     {
         host.Open();
  
         StorageAccountInfo account = 
             EchoFacadeTest.GetAccount();
         EchoFacade sut = new EchoFacade(() => account);
         // Exercise system
         sut.Delay(expectedMessage);
         // Verify outcome
         Assert.AreEqual<string>(expectedMessage,
             service.Container.GetStore<FakeMessage>().
             First().Message, "Delay");
         // Teardown
     }
 }

In the EchoFacade service, I've used the SDK sample StorageClient library that extents the ADO.NET Data Services Client API to deal with the particulars of Windows Azure Table Storage. One difference from regular ADO.NET Data Services lies in how StorageClient deals with the base URIs of the REST interface. This is a challenge, because a URI like https://localhost/EchoService is interpreted as a service at the address localhost belonging to the account EchoService.

This has the implication that I can't just pass the complete address directly to the client API (i.e. EchoFacade), since it would need to decompose it before it can make proper use of it. Fortunately, such a decomposition already exists in the form of the StorageAccountInfo class, so I just need to pass a properly configured instance to my SUT to make it work.

The test accomplishes this task like this:

 private static StorageAccountInfo GetAccount()
 {
     Uri address = new Uri("https://localhost/");
     return new StorageAccountInfo(address, true,
         "EchoService", EchoFacadeTest.TableKey);
 }

When the service is hosted in the full system (whether in the Development Fabric or on Azure proper), the StorageAccountInfo instance is instead initialized using the static StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration method.

If you are using the StorageClient library for your data access code, you might as well also take advantage of it when defining the fake service. First of all, you can derive the entities exposed from the Fake service from TableStorageEntity, as this gives you the key properties for free.

 public class FakeMessage : TableStorageEntity
 {
     public FakeMessage()
     {
         this.CreationTime = DateTime.Now;
     }
  
     public DateTime CreationTime { get; set; }
  
     public string Message { get; set; }
 }

The DataContainer then becomes equally simple:

 public class MessageContainer : DataContainer
 {
     public IQueryable<FakeMessage> Messages
     {
         get
         { 
             return this.GetStore<FakeMessage>().
                 AsQueryable(); 
         }
     }
 }

Using a Fake ADO.NET Data Service enables you unit test clients of the Windows Azure Table Service in a light-weight manner.

In this Fake, I have chosen not to deal with the Windows Azure Table Service's particular way of partitioning and sorting data according to PartitionKey and RowKey. Instead, I just rely on the Fixture of each test to insert the data entities in the expected order.

Comments

  • Anonymous
    January 08, 2011
    Can you post the full solution for this? I would be very interested in seeing how it all comes together.