Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Azure

Working with Data in the Surveys Application : Testing and Windows Azure Storage

6/20/2011 5:30:52 PM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
1. Goals and Requirements

The Surveys application uses Windows Azure table and BLOB storage, and the developers at Tailspin were concerned about how this would affect their unit testing strategy. From a testing perspective, a unit test should focus on the behavior of a specific class and not on the interaction of that class with other components in the application. From the perspective of Windows Azure, any test that depends on Windows Azure storage requires complex setup and tear-down logic to make sure that the correct data is available for the test to run. For both of these reasons, the developers at Tailspin designed the data access functionality in the Surveys application with testability in mind, and specifically to make it possible to run unit tests on their data store classes without a dependency on Windows Azure storage.

2. The Solution

The solution adopted by the developers at Tailspin was to wrap the Windows Azure storage components in such a way as to facilitate replacing them with mock objects during unit tests and to use the Unity Application Block (Unity). A unit test should be able to instantiate a suitable mock storage component, use it for the duration of the test, and then discard it. Any integration tests can continue to use the original data access components to test the functionality of the application.


Note:

The Surveys application uses Unity to decouple its components and facilitate testing.



Note:

Unity is a lightweight, extensible dependency injection container that supports interception, constructor injection, property injection, and method call injection. You can use Unity in a variety of ways to help decouple the components of your applications, to maximize coherence in components, and to simplify design, implementation, testing, and administration of these applications.

You can learn more about Unity and download the application block at http://unity.codeplex.com/.


3. Inside the Implementation

Now is a good time to walk through some code that illustrates testing the store classes in more detail. As you go through this section, you may want to download the Microsoft® Visual Studio® development system solution for the Tailspin Surveys application from http://wag.codeplex.com/.

This section describes how the design of the Surveys application supports unit testing of the SurveyStore class that provides access to the table storage. This description focuses on one specific set of tests, but the application uses the same approach with other store classes.

The following code example shows the IAzureTable interface and the AzureTable class that are at the heart of the implementation.

public interface IAzureTable<T> where T : TableServiceEntity
{

IQueryable<T> Query { get; }
void EnsureExist();
void Add(T obj);
void Add(IEnumerable<T> objs);
void AddOrUpdate(T obj);
void AddOrUpdate(IEnumerable<T> objs);
void Delete(T obj);
void Delete(IEnumerable<T> objs);
}

public class AzureTable<T>
: IAzureTable<T> where T : TableServiceEntity
{

private readonly string tableName;
private readonly CloudStorageAccount account;

...

public IQueryable<T> Query
{
get
{
TableServiceContext context = this.CreateContext();
return context.CreateQuery<T>(this.tableName)
.AsTableServiceQuery();
}
}

public void Add(T obj)
{
this.Add(new[] { obj });
}

public void Add(IEnumerable<T> objs)
{
TableServiceContext context = this.CreateContext();

foreach (var obj in objs)
{
context.AddObject(this.tableName, obj);
}

var saveChangesOptions = SaveChangesOptions.None;
if (objs.Distinct(new PartitionKeyComparer())
.Count() == 1)
{
saveChangesOptions = SaveChangesOptions.Batch;
}

context.SaveChanges(saveChangesOptions);
}

...

private TableServiceContext CreateContext()
{
return new TableServiceContext(
this.account.TableEndpoint.ToString(),
this.account.Credentials);
}

private class PartitionKeyComparer :
IEqualityComparer<TableServiceEntity>
{
public bool Equals(TableServiceEntity x,
TableServiceEntity y)
{
return string.Compare(x.PartitionKey, y.PartitionKey,
true,
System.Globalization.CultureInfo
.InvariantCulture) == 0;
}

public int GetHashCode(TableServiceEntity obj)
{
return obj.PartitionKey.GetHashCode();
}
}
}

The generic interface and class have a type parameter T that derives from the Windows Azure TableServiceEntity type that you use to create your own table types. For example, in the Surveys application, the SurveyRow and QuestionRow types derive from the TableServiceEntity class. The interface defines several operations: the Query method returns an IQueryable collection of the type T, and the Add, AddOrUpdate, and Delete methods each take a parameter of type T. In the AzureTable class, the Query method returns a TableServiceQuery object, the Add and AddOrUpdate methods save the object to table storage, and the Delete method deletes the object from table storage. To create a mock object for unit testing, you must instantiate an object of type IAzureTable.

The following code example from the SurveyStore class shows the constructor.

public SurveyStore(IAzureTable<SurveyRow> surveyTable,
IAzureTable<QuestionRow> questionTable)
{

this.surveyTable = surveyTable;
this.questionTable = questionTable;
}

The constructor takes parameters of type IAzureTable that enable you to pass in either real or mock objects that implement the interface.

This parameterized constructor is invoked in two different scenarios. The Surveys application invokes the constructor indirectly when the application uses the SurveysController MVC class. The application uses the Unity dependency injection framework to instantiate MVC controllers. The Surveys application replaces the standard MVC controller factory with the UnityControllerFactory class in the OnStart method in both web roles, so when the application requires a new MVC controller instance, Unity is responsible for instantiating that controller. The following code example shows part of the ContainerBootstrapper class from the TailSpin.Web project that the Unity container uses to determine how to instantiate objects.

public static class ContainerBootstraper
{
public static void RegisterTypes(IUnityContainer container)
{
var account = CloudConfiguration
.GetStorageAccount("DataConnectionString");
container.RegisterInstance(account);

container.RegisterType<ISurveyStore, SurveyStore>();

container.RegisterType<IAzureTable<SurveyRow>,
AzureTable<SurveyRow>>(
new InjectionConstructor(typeof
(Microsoft.WindowsAzure.CloudStorageAccount),
AzureConstants.Tables.Surveys));

container.RegisterType<IAzureTable<QuestionRow>,
AzureTable<QuestionRow>>(
new InjectionConstructor(typeof
(Microsoft.WindowsAzure.CloudStorageAccount),
AzureConstants.Tables.Questions));


...
}

}

The last two calls to the RegisterType method define the rules that tell the Unity container how to instantiate the AzureTable instances that it must pass to the SurveyStore constructor.

When the application requires a new MVC controller instance, Unity is responsible for creating the controller, and in the case of the SurveysController class, Unity instantiates a SurveyStore object using the parameterized constructor shown earlier, and passes the SurveyStore object to the SurveysController constructor.

In the second usage scenario for the parameterized SurveyStore constructor, you create unit tests for the SurveyStore class by directly invoking the constructor and passing in mock objects. The following code example shows a unit test method that uses the constructor in this way.

[TestMethod]
public void GetSurveyByTenantAndSlugNameReturnsTenantNameFrom
PartitionKey()
{
string expectedRowKey = string.Format(
CultureInfo.InvariantCulture, "{0}_{1}", "tenant",
"slug-name");
var surveyRow = new SurveyRow { RowKey = expectedRowKey,
PartitionKey = "tenant" };
var surveyRowsForTheQuery = new[] { surveyRow };
var mock = new Mock<IAzureTable<SurveyRow>>();
mock.SetupGet(t => t.Query)
.Returns(surveyRowsForTheQuery.AsQueryable());
var store = new SurveyStore(mock.Object,
default(IAzureTable<QuestionRow>));

var survey = store.GetSurveyByTenantAndSlugName("tenant",
"slug-name", false);

Assert.AreEqual("tenant", survey.Tenant);
}

The test creates a mock IAzureTable<SurveyRow> instance, uses it to instantiate a SurveyStore object, invokes the GetSurveyByTenantAndSlugName method, and checks the result. It performs this test without touching Windows Azure table storage.

The Surveys application uses a similar approach to enable unit testing of the other store components that use Windows Azure BLOB and table storage.

Other -----------------
- Working with Data in the Surveys Application : A Data Model for a Multi-Tenant Application
- Enterprise Application Development : Azure Monitoring and Diagnostics
- Enterprise Application Development : Azure Diagnostics­ under the hood & Enabling diagnostic logging
- Building a Scalable, Multi-Tenant Application for Windows Azure : Scaling the Surveys Application
- Building a Scalable, Multi-Tenant Application for Windows Azure : Scaling Applications by Using Worker Roles
- Building a Scalable, Multi-Tenant Application for Windows Azure : On-Boarding for Trials and New Customers
- Introduction to SQL Azure : Creating our database
- Introduction to SQL Azure : Migrating schema and data
- Introduction to SQL Azure
- Overview of SQL Azure
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server