Blendable MVVM: Dependency Injection and Unit Testing

Posted Sunday, October 11, 2009 by

There are a couple of great reasons for using a UI separation pattern such as Model, View, ViewModel (or the more common MVP and MVC), the first being that with the application logic separated from the view logic the application becomes easier to maintain. Secondly it's usually easier for a designer and developer to work on the separate areas and integrate them at a later date (this actually helps enforce the separation). And thirdly by having the application logic away from the UI it becomes much easier to test.

While you can do UI testing with the Silverlight testing framework it becomes a hell of a lot easier when you have a nice separation. We're doing to be using a dependency injection framework (in this caseNinject) to build the view models and inject the services. This'll allow us to do interaction based unit testing on the view model using Rhino Mocks.

Overall our goal will be to refactor the existing ViewModel to break it's dependency on CocktailsService and increase it's testability. We'll create a Service Locator that will be an Application resource and serve as almost a "ViewModel factory" and then instead of directly creating our ViewModel in xaml we'll bind our Data Context to the Service Locator.

Our first step will be inverting the dependency the ViewModel has on the Cocktails Service, we'll extract an interface for the service and use constructor injection to pass the service to the ViewModel where it'll be stored, otherwise the view model remains the same.

public interface ICocktailService

{

    IEnumerable<Cocktail> GetCocktails();

    IEnumerable<Cocktail> GetCocktailsSimilarTo(Cocktail cocktail);

}

public CocktailsViewModel(ICocktailService cocktailService)

{

    this.cocktailService = cocktailService;

 

    AvailableCocktails = new ObservableCollection<Cocktail>();

    SimilarCocktails = new ObservableCollection<Cocktail>();

 

    GetSimilarCocktailsCommand = new DelegateCommand<Cocktail>(GetSimilarCocktails);

 

    AvailableCocktails.AddRange(cocktailService.GetCocktails());

}

We can now test that the ViewModel exposes the available Cocktails, passes the command parameter to the service and exposes the similar cocktails.

[TestClass]

public class CocktailsViewModelFixture

{

    private readonly List<Cocktail> sampleCocktails = new List<Cocktail>

        {

            new Cocktail

            {

                Id = 1,

                Ingredients = new string[] {},

                Name = "Test"

            }

        };

 

    [TestMethod]

    public void ConstuctionRetrievesAvailableCockstails()

    {

        var cocktailService = MockRepository.GenerateMock<ICocktailService>();

 

        cocktailService.Expect(c => c.GetCocktails()).Return(Enumerable.Empty<Cocktail>());

 

        new CocktailsViewModel(cocktailService);

 

        cocktailService.VerifyAllExpectations();

    }

 

    [TestMethod]

    public void ConstuctionExposesAvailableCockstails()

    {

        var cocktailService = MockRepository.GenerateStub<ICocktailService>();

 

        cocktailService.Stub(c => c.GetCocktails()).Return(sampleCocktails);

 

        var viewModel = new CocktailsViewModel(cocktailService);

 

        Assert.AreEqual(sampleCocktails.Count, viewModel.AvailableCocktails.Count);

    }

 

    [TestMethod]

    public void GetSimilarCocktailsForwardsCommandParameter()

    {

        var selectedCocktail = new Cocktail();

 

        var cocktailService = MockRepository.GenerateMock<ICocktailService>();

 

        cocktailService.Stub(c => c.GetCocktails()).Return(Enumerable.Empty<Cocktail>());

        cocktailService.Expect(c => c.GetCocktailsSimilarTo(selectedCocktail)).Return(Enumerable.Empty<Cocktail>());

 

        var viewModel = new CocktailsViewModel(cocktailService);

 

        viewModel.GetSimilarCocktailsCommand.Execute(selectedCocktail);

 

        cocktailService.VerifyAllExpectations();

    }

 

    [TestMethod]

    public void GetSimilarCocktailsExposesSimilarCocktails()

    {

        var selectedCocktail = new Cocktail();

 

        var cocktailService = MockRepository.GenerateMock<ICocktailService>();

 

        cocktailService.Stub(c => c.GetCocktails()).Return(Enumerable.Empty<Cocktail>());

        cocktailService.Stub(c => c.GetCocktailsSimilarTo(selectedCocktail)).Return(sampleCocktails);

 

        var viewModel = new CocktailsViewModel(cocktailService);

 

        viewModel.GetSimilarCocktailsCommand.Execute(selectedCocktail);

 

        Assert.AreEqual(sampleCocktails.Count, viewModel.SimilarCocktails.Count);

    }

}

Astute readers will notice that because our ViewModel doesn't have a parameterless constructor we can't create it directly in xaml. This is correct, instead we'll be delegating the construction of the ViewModel to a Ninject kernel. We'll create a ServiceLocator that will be an Application Resource (in App.xaml), it will create the Ninject kernel and register the appropriate dependencies.

public class ServiceLocator

{

    private readonly IKernel kernal;

 

    public ServiceLocator()

    {

        kernal = new StandardKernel(new CocktailModule());

    }

 

    public CocktailsViewModel CocktailsViewModel

    {

        get

        {

            return kernal.Get<CocktailsViewModel>();

        }

    }

}

public class CocktailModule : StandardModule

{

    public override void Load()

    {

        Bind<CocktailsViewModel>().ToSelf();

        Bind<ICocktailService>().To<CocktailService>();

    }

}

 

<Application.Resources>

    <cx:ServiceLocator x:Key="ServiceLocator"/>

</Application.Resources>

For simplicities sake I have a simple module that will register the dependencies we need.

Unfortunately there's no nice GUI to hook the ViewModel up anymore we have to write our own Binding expression, but it's not too bad. This binds the DataContext of the UserControl to the property "CocktailsViewModel" which is in turn created by the Ninject kernal, injecting the appropriate dependencies.

DataContext="{Binding Path=CocktailsViewModel,Source={StaticResource ServiceLocator}}"

We're now back to where we were before but now with a unit tested view model. Later on I'll do a post on integration testing the entire stack.

Shout it kick it on DotNetKicks.com

Update to DI Container initialization

Posted Thursday, March 13, 2008 by

 Since I wrote the earlier code in "Using LINQ to initialize DI Containers" I've cleaned up the LINQ query to incorporate the assemblies loop and also to use the First extension method to make things a bit more readable.

var services = from a in assemblies

               from t in Assembly.Load(a).GetTypes()

               where t.GetInterfaces().Length > 0 && t.IsSubclassOf(typeof(ServiceBase))

               let i = t.GetInterfaces().First()

               where !Container.Kernel.HasComponent(i)

               select new

               {

                   Interface = i.IsGenericType ? i.GetGenericTypeDefinition() : i,

                   Component = t

               };

 

foreach(var service in services)

{

    Container.AddComponent(service.Interface.FullName, service.Interface, service.Component);

}

 

 

Using LINQ to initialize DI Containers

Posted Sunday, March 9, 2008 by

Recently there have been some discussion on how to help initialize dependency injection containers. Ayende call this "Setting up Zero Fiction Projects" and uses the Boo language to create a DSL (Domain Specific Language) to specify components to be registered into the container. From hammet comes news around a fluent interface for adding components to Castle Windsor. The essence of both is to find all types in a given assembly that either implement a certain a certain interface or are a subclass of a layer supertype (I tend to have a ServiceBase that contains things Log and so on). We can use LINQ to achieve something similar to both the above approaches.

public static void RegisterControllers(params string[] assemblies)

{

    foreach(string assembly in assemblies)

    {

        IEnumerable<Type> controllers = from t in Assembly.Load(assembly).GetTypes()

                                        where t.Implements<IController>()

                                        select t;

 

        foreach(Type controller in controllers)

        {

            Container.AddComponentWithLifestyle(controller.FullName, controller, LifestyleType.Transient);

        }

    }

}

 

The above code iterates a list of assembly names and finds all types that implement the ASP.NET MVC IController interface. To increase the readability of the LINQ query I've used an extension method listed below.

public static bool Implements<T>(this Type type)

{

    return typeof(T).IsAssignableFrom(type);

}

 

The below code locates the first interface for the service and uses that as the service to register the type. Depending on how you create your types this may or may not be a good method. Using the Repository class I've described before doesn't allow this approach as it is the last interface that becomes the important one, however I've used this code to show some similar functionality as the examples above. Hope this helps someone.

public static void RegisterServices(params string[] assemblies)

{

    foreach(string assembly in assemblies)

    {

        var services = from t in Assembly.Load(assembly).GetTypes()

                       where t.GetInterfaces().Length > 0 && t.IsSubclassOf(typeof(ServiceBase))

                       let i = t.GetInterfaces()[0]

                       where !Container.Kernel.HasComponent(i)

                       select new

                       {

                           Interface = i.IsGenericType ? i.GetGenericTypeDefinition() : i,

                           Component = t

                       };

 

        foreach(var service in services)

        {

            Container.AddComponent(service.Interface.FullName, service.Interface, service.Component);

        }

    }

}

Page 1 of 11

Professional Windows App Development