Faking out Azure - Unit Testing with Microsoft Fakes

Overview

Microsoft Fakes provides an excellent framework for code isolation within Unit Tests and is only available for Visual Studio Enterprise subscriptions. Fakes do provide advantages over other frameworks (re., Moq and Rhino Mocks) as it allows for full code isolation and not just interfaces or public virtual members.  There are alternatives to Fakes (e.g., Telerik JustMock and TypeMocks).

The MSDN project, Azure Storage and Microsoft Fakes, was created to show some of the cool things Microsoft Fakes provides when isolating Azure Storage.

Please see the project for more information and the following is shown here as an overview.

Sample

To illustrate a simple class, StorageManager, was created to send an update a product to an Azure Storage Table called Products.  The entire class is shown below:

C#

Edit|Remove

namespace MSDNFakeOutStorage 
{ 
    public class StorageManager 
    { 
        public bool UpdateProducts(ProductEntity entity) 
        { 
            var table = GetClientForTable("Products"); 
 
            var result = table.Execute(TableOperation.InsertOrReplace(entity)); 
 
            return result.HttpStatusCode == 204; 
        } 
 
        private readonly string ConnectionString = ConfigurationManager.AppSettings["AzureStorageConnectionString"]; 
 
        private CloudTable GetClientForTable(string tableName) 
        { 
            var account = CloudStorageAccount.Parse(ConnectionString); 
 
            var tableClient = account.CreateCloudTableClient(); 
            var table = tableClient.GetTableReference(tableName); 
 
            table.CreateIfNotExists(); 
 
            return table; 
        } 
 
    } 
}

We will create two basic tests.  One to test how the StorageManager behaves when the Products table is successfully updated and when it is not updated successfully.  

To start we need to add to fakes to our project: Microsoft.WindowsAzure.Storage and System.Configuration:

https://code.msdn.microsoft.com/site/view/file/158055/1/ms1.jpg

The following shows the generated fakes in the project:

https://code.msdn.microsoft.com/site/view/file/158056/1/ms2.jpg

Unit Test - System.Configuration

The first step is to isolate the ConfigurationManager.AppSettings from the StorageManager.ConnectionString.  The following will divert all ConfigurationManager.AppSettings[] calls to a new NameValueCollection and is shown below:

C#

Edit|Remove

ShimConfigurationManager.AppSettingsGet = () => 
{ 
    var settings = new NameValueCollection(); 
    settings.Add("AzureStorageConnectionString", "valueOfAzureStorageConnectionString"); 
 
    return settings; 
};

When debugging the unit test you can see the magic working:

https://code.msdn.microsoft.com/site/view/file/158057/1/ms3.jpg 

Unit Test - Microsoft.WindowsAzure.Storage

The next step is to create a shim for the Azure Storage components used in the project.  A shim was used instead of a stub as we are not replacing the entire object but only diverting messages to our test functionality.  

In the code snippet below, note how all calls from the StorageManager class to the underlying storage classes are supplied:

C#

Edit|Remove

ShimCloudStorageAccount.ParseString = (connectionString) => 
{ 
    if (connectionString != "valueOfAzureStorageConnectionString") 
        Assert.Fail(string.Format($"Unexpected connection string value of {connectionString} received!")); 
 
    return new ShimCloudStorageAccount 
    { 
        CreateCloudTableClient = () => new ShimCloudTableClient 
        { 
            GetTableReferenceString = (tableName) => 
            { 
                if (tableName != "myTable") 
                    Assert.Fail("The table name should be Products"); 
 
                return new ShimCloudTable 
                { 
                    CreateIfNotExistsTableRequestOptionsOperationContext = (requestOptions, operationContext) => true, 
                    ExecuteTableOperationTableRequestOptionsOperationContext = (operation, requestOptions, context) => 
                    { 
                        return new TableResult 
                        { 
                            // successful response code is No Content 
                            // https://msdn.microsoft.com/en-us/library/azure/hh452242.aspx 
                            HttpStatusCode = 204 
                        }; 
                    } 
                }; 
            } 
        } 
    }; 
}; 

Summary

This article provides an example of how Microsoft Fakes can isolate Azure Storage from code.  Microsoft Fakes empowers some developers to write complete unit tests and for others helps to reduce the credibility of using the "It's too hard" excuse in avoiding to write unit tests.

More Information