Published by fboerr on July 23rd, 2010 6:27 pm under Emerging Technology, azure
1 CommentDuring 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.
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.
public class SurveyStore : ISurveyStore { private readonly CloudStorageAccount account; public SurveyStore(CloudStorageAccount account) public IEnumerable<Survey> GetSurveysByTenant(string tenant) var cloudTableClient = new CloudTableClient(this.account.TableEndpoint.ToString(), this.account.Credentials); TableServiceContext context = this.CreateContext(); var query = (from s in context.CreateQuery<SurveyRow>(“SurveysTable”) return query.Execute().Select(surveyRow => new Survey(surveyRow.SlugName) |
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 …) }; var store = new ExpenseStore(); Assert.AreEqual(1, expenses.Count()); (Assert other properties …) |
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.
public class SurveyStore : ISurveyStore { private readonly IAzureTable<SurveyRow> surveyTable; public SurveyStore(IAzureTable<SurveyRow> surveyTable) public IEnumerable<Survey> GetSurveysByTenant(string tenant) return query.ToList().Select(surveyRow => new Survey(surveyRow.SlugName) |
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); |
Twitter Trackbacks for Federico Boerr’s Blog » Blog Archive » Windows Azure Storage: TDD and mocks [southworks.net] on Topsy.com said on July 23, 2010:
[...] Federico Boerr’s Blog » Blog Archive » Windows Azure Storage: TDD and mocks blogs.southworks.net/fboerr/2010/07/23/windows-azure-storage-tdd-and-mocks/ – view page – cached During the last months, we have been working on a sample application for the Windows Azure Architecture Guide. Tweets about this link [...]
Your email address will not be published.