• Windows Azure Storage: TDD and mocks

    Published by on July 23rd, 2010 6:27 pm under azure, Emerging Technology

    4 Comments

    During the last months, we have been working on a sample application for the Windows Azure Architecture Guide.

    One of the challenges we want to face in the development side is to develop the majority of the sample application following TDD practices.

    This post shows how we mocked-up Azure Storage Tables by using a IAzureTable interface. Similar interfaces have been develop for queues (IAzureQueue) and blobs (IAzureBlobContainer).

    Thanks Johnny Halife (@johnnyhalife), Juan Pablo Garcia (@jpgd) and Scott Densmore (@scottdensmore). These classes have been designed after long discussions with you guys so you also hold credit for them.

    Directly using WindowsAzure.StorageClient (from Windows Azure SDK)

    When developing applications for Windows Azure, the most used  library for accessing the Azure Storage is the Storage Client (Microsoft.WindowsAzure.StorageClient) that comes as part of the Windows Azure SDK.

    As an example, let’s imagine we are developing the SurveyStore (this class is part of the Storage component in the diagram above). This class that is called from the controllers and interacts with the persistence stores.

    image

    SurveyStore using WindowsAzure.StorageClient

    public class SurveyStore : ISurveyStore
    {
    private readonly CloudStorageAccount account;

    public SurveyStore(CloudStorageAccount account)
    {
    this.account = account;
    }

    public IEnumerable<Survey> GetSurveysByTenant(string tenant)
    {

    var cloudTableClient = new CloudTableClient(this.account.TableEndpoint.ToString(), this.account.Credentials);
    cloudTableClient.CreateTableIfNotExist(“SurveysTable”);

    TableServiceContext context = this.CreateContext();

    var query = (from s in context.CreateQuery<SurveyRow>(“SurveysTable”)
    where s.PartitionKey == tenant
    select s).AsTableServiceQuery();

    return query.Execute().Select(surveyRow => new Survey(surveyRow.SlugName)
    {
    Tenant = surveyRow.PartitionKey,
    Title = surveyRow.Title,
    CreatedOn = surveyRow.CreatedOn
    }).ToList();
    }
    }

    Testing this implementation

    If we want to write a test for this method, this would be a functional test because there is no way to mockup the calls to CloudTableClient and to TableServiceContext.

    Every time we run the test, we have to:

    1. Ensure the data we will query is exactly what we are expecting to get (2 calls to the real Surveys Table in the Azure storage)

    2. Call GetSurveysByTenant (1 call to the real Surveys Table in the Azure storage)

    3. Assert that we got what we were expecting from the store

    [TestMethod]
    public void GetSurveysByTenant()
    {
    var expenseContext = AzureStorageHelper.GetContext();

    var expected = new Expense { Tenant = “Tenant”,  (… initialize other properties …) };
    expected.Details.Add(new ExpenseItem { (… initialize all properties …) });
    AzureStorageHelper.DeleteExpenseAndItemsById(expenseContext, expected.Id);
    AzureStorageHelper.SaveExpense(expenseContext, expected);

    var store = new ExpenseStore();
    var expenses = store.GetSurveysByTenant(“Tenant”);

    Assert.AreEqual(1, expenses.Count());
    var actual = expenses.Single(e => e.Id == expected.Id);
    Assert.AreEqual(“Tenant”, actual.Tenant);

    (Assert other properties …)
    }

    Wrapping WindowsAzure.StorageClient with an IAzureTable

    In the case our development is driven by TDD or we just want to write unit tests on any class that has to interact with Windows Azure Storage, we find a problem with the implementation shown above.

    Working with CloudTableClient or TableServiceContext will not allow us to write *unit* tests. Testing the previous implementation, implied not only testing the SurveyStore class code, but also the code to access the Windows Azure Table itself. The ONLY way to test the SurveyStore code, is writing stubs and mocks for the code that access the Windows Azure Table.

    This implementation also follows a good object-oriented design: “Program to an ‘interface’, not an ‘implementation'” and provides all its advantages.

    SurveyStore using IAzureTable

    public class SurveyStore : ISurveyStore
    {
    private readonly IAzureTable<SurveyRow> surveyTable;

    public SurveyStore(IAzureTable<SurveyRow> surveyTable)
    {
    this.surveyTable = surveyTable;
    }

    public IEnumerable<Survey> GetSurveysByTenant(string tenant)
    {
    var query = from s in this.surveyTable.Query
    where s.PartitionKey == tenant
    select s;

    return query.ToList().Select(surveyRow => new Survey(surveyRow.SlugName)
    {
    Tenant = surveyRow.PartitionKey,
    Title = surveyRow.Title,
    CreatedOn = surveyRow.CreatedOn
    });
    }
    }

    Testing this implementation

    Testing this implementation is easier and let us focus ONLY in 1 part at a time.

    In this example, we are only testing that the method GetSurveysByTenant correctly copies the title from the row read from the IAzureTable (SurveysTable) to the returned survey.

    By mocking the IAzureTable, we can setup what the Query property is going to return, so there is no need to interact with the Windows Azure Storage itself. Remember that in the previous implementation we had to make 3 calls to the Windows Azure Table. Here, we are making no calls to the Windows Azure Table.

    [TestMethod]
    public void GetSurveysByTenantReturnsTitle()
    {
    var surveyRow = new SurveyRow { PartitionKey = “tenant”, Title = “title” };
    var surveyRowsToReturn = new[] { surveyRow };
    var mock = new Mock<IAzureTable<SurveyRow>>();
    mock.SetupGet(t => t.Query).Returns(surveyRowsToReturn.AsQueryable());
    var store = new SurveyStore(mock.Object, default(IAzureTable<QuestionRow>));

    var actualSurveys = store.GetSurveysByTenant(“tenant”);

    Assert.AreEqual(“title”, actualSurveys.First().Title);
    }