TDD and Dependency Injection with ASP.NET MVC

asp.net, code, asp.net mvc, tdd 0 comments suggest edit

One of the guiding principles in the design of the new ASP.NET MVC Framework is enabling TDD (Test Driven Development) when building a web application. If you want to follow along, this post makes use of ASP.NET MVC CodePlex Preview 4 which you’ll need to install from CodePlex. I’ll try and keep this post up to date with the latest releases, but it may take me time to get around to it.

This post will provide a somewhat detailed walk-through of building a web application in a Test Driven manner while also demonstrating one way to integrate a Dependency Injection (DI) Framework into an ASP.NET MVC app. At the very end, you can download the code.

I chose StructureMap 2.0 for the DI framework simply because I’m familiar with it and it requires very little code and configuration. If you’re interested in an example using Spring.NET, check out Fredrik Normen’s post. I’ll try and post code examples in the future using Castle Windsor and ObjectBuilder.

Start Me Up! with apologies to The Rolling Stones

Once the CTP is released and you have it installed, open Visual Studio 2008 and select the File | New Projectmenu item. In the dialog, select the ASP.NET MVC Web Applicationproject template.

New
Project

At this point, you should see the following unit test project selection dialog.

Select Unit Test
Project

In a default installation, only the Visual Studio Unit Test project option is available. But MbUnit, xUnit.NET and others have installers available to get their test frameworks in this dialog.

As you might guess, I’ll start off building the canonical blog demo. I am going to start without using a database. We can always add that in later.

The first thing I want to do is add a few classes to the main project. I won’t add any implementation yet, I just want something to compile against. I’m going to add the following:

  • BlogController.cs to the Controllers directory
  • IPostRepository.cs to the Models directory
  • Post.cs to the Models directory
  • BlogControllerTests to the MvcApplicationTest project.

After I’m done, my project tree should look like this.

 Project
Tree

At this point, I want to implement just enough code so we can write a test. First, I define my repository interface.

using System;
using System.Collections.Generic;

namespace MvcApplication.Models
{
  public interface IPostRepository
  {
    void Create(Post post);

    IList<Post> ListRecentPosts(int retrievalCount);
  }
}

Not much of a blog post repository, but it’ll do for this demo. When you’re ready to write the next great blog engine, you can revisit this and add more methods.

Also, I’m going to leave the Post class empty for the time being. We can implement that later. Let’s implement the blog controller next.

using System;
using System.Web.Mvc;

namespace MvcApplication.Controllers 
{
  public class BlogController : Controller 
  {
    public ActionResult Recent() 
    {
      throw new NotImplementedException("Wait! Gotta write a test first!");
    }
  }
}

Ok, we better stop here. We’ve gone far enough without writing a unit test. After all, I’m supposed to be demonstrating TDD. Let’s write a test.

Let’s Get Test Started, In Here. with apologies to the Black Eyed Peas

Starting with the simplest test possible, I’ll make sure that the Recent action does not specify a view name because I want the default behavior to apply (this snippet assumes you’ve imported all the necessary namespaces).

[TestClass]
public class BlogControllerTests 
{
  [TestMethod]
  public void RecentActionUsesConventionToChooseView() 
    {
    //Arrange
    var controller = new BlogController();

    //Act
    var result = controller.Recent() as ViewResult;

    //Assert
    Assert.IsTrue(String.IsNullOrEmpty(result.ViewName));
  }
}

When I run this test, the test fails.

failed-test

This is what we expect, after all, we haven’t yet implemented the Recent method. This is the RED part of the RED, GREEN, REFACTOR rhythm of TDD.

Let’s go and implement that method.

public ActionResult Recent() 
{
  //Note we haven’t yet created a view
  return View();
}

Notice that at this point, we’re focusing on the behavior of our app first rather than focusing on the UI first. This is a stylistic difference between ASP.NET MVC and ASP.NET WebForms. Neither one is necessarily better than the other. Just a difference in approach and style.

Now when I run the unit test, it passes.

passing-test 

Ok, so that’s the GREEN part of the TDD lifecycle and a very very simple demo of TDD. Let’s move to the REFACTOR stage and start applying Dependency Injection.

It’s Refactor Time! with apologies to the reader for stretching this theme too far

In order to obtain the recent blog posts, I want to provide my blog controller with a “service” instance it can request those posts from. 

At this point, I’m not sure how I’m going to store my blog posts. Will I use SQL? XML? Stone Tablet?

Dunno. Don’t care… yet.

We can delay that decision till the last responsible moment. For now, I’ll create a repository abstraction to represent how I will store and retrieve blog posts in the form of an IPostRepository interface. We’ll update the blog controller to accept an instance of this interface in its constructor.

This is the dependency part of Dependency Injection. My controller now has a dependency on IPostRepository. The injection part refers to the mechanism you use to pass that dependency to the dependent class as opposed to having the class create that instance directly and thus binding the class to a specific implementation of that interface.

Here’s the change to my BlogController class.

public class BlogController : Controller 
{
  IPostRepository repository;

  public BlogController(IPostRepository repository) 
  {
    this.repository = repository;
  }

  public ActionResult Recent() 
  {
    //Note we haven’t yet created a view
    return View();
  }
}

Great. Notice I haven’t changed Recent yet. I need to write another test first. This will make sure that we pass the proper data to the view.

Note: If you’re following along, you’ll notice that the first test we wrote won’t compile. Comment it out for now. We can fix it later.

I’m going to use a mock framework, so before I write this test, I need to reference Moq.dll in my test project, downloaded from the MoQ downloads page.

Note: I’ve included this assembly in the example project at the end of this post.

Here’s the new test.

[TestMethod]
public void BlogControllerPassesCorrectViewData() 
{
  //Arrange
  var posts = new List<Post>();
  posts.Add(new Post());
  posts.Add(new Post());

  var repository = new Mock<IPostRepository>();
  repository.Expect(r => r.ListRecentPosts(It.IsAny<int>())).Returns(posts);

  //Act
  BlogController controller = new BlogController(repository.Object);
  var result = controller.Recent() as ViewResult;

  //Assert
  var model = result.ViewData.Model as IList<Post>;
  Assert.AreEqual(2, model.Count);
}

What this test is doing is dynamically stubbing out an implementation of the IPostRepository interface. We then tell it that no matter what argument is passed to ListRecentPosts, return two posts. We can then pass that stub to our controller.

Note: We haven’t yet needed to implement this interface. We don’t need to yet. We’re interested in isolating our test to only test the logic in the action method, so we fake out the interface for the time being.

At this point, the test fails as we expect. We need to refactor Recent to do the right thing now.

public ActionResult Recent() 
{
  IList<Post> posts = repository.ListRecentPosts(10); //Doh! Magic Number!
  return View(posts);
}

Now when I run my test, it passes!

Inject That Dependency

But we’re not done yet. When I load up a browser and try to navigate to this controller action (on my machine, http://localhost:64701/blog/recent/), I get the following error page.

No parameterless constructor defined for this object. - Mozilla
Firefox

Well of course it errors out! By default, ASP.NET MVC requires that controllers have a public parameter-less constructor so that it can create an instance of the controller. But our constructor requires an instance of IPostRepository. We need someone, anyone, to pass such an instance to our controller.

StructureMap (or DI framework of your choice) to the rescue!

Note: Make sure todownloadand reference the StructureMap.dll assembly if you’re following along. I’ve included the assembly in the source code at the end of this post.

The first step I’m going to do is create a StructureMap.config file and add it to the root of my application. Here are the contents of the file.

<?xml version="1.0" encoding="utf-8" ?>
<StructureMap>
  <Assembly Name="MvcApplication" />
  <Assembly Name="System.Web.Mvc
              , Version=1.0.0.0
              , Culture=neutral
              , PublicKeyToken=31bf3856ad364e35" />

  <PluginFamily Type="System.Web.Mvc.IController" 
                Assembly="System.Web.Mvc
                  , Version=1.0.0.0
                  , Culture=neutral
                  , PublicKeyToken=31bf3856ad364e35">
    <Plugin Type="MvcApplication.Controllers.BlogController" 
            ConcreteKey="blog" 
            Assembly="MvcApplication" />
  </PluginFamily>

  <PluginFamily Type="MvcApplication.Models.IPostRepository" 
                Assembly="MvcApplication" 
                DefaultKey="InMemory">
    <Plugin Assembly="MvcApplication" 
            Type="MvcApplication.Models.InMemoryPostRepository" 
            ConcreteKey="InMemory" />
  </PluginFamily>

</StructureMap>

I don’t want to get bogged down in describing this file in too much detail. If you want a deeper understanding, check out the StructureMap documentation.

The bare minimum you need to know is that each PluginFamily node describes an interface type and a key for that type. A Plugin node describes a concrete type that will be used when an instance of the family type needs to be created by the framework.

For example, in the second PluginFamily node, the interface type is  IPostRepository which we defined. The concrete type is InMemoryPostRepository. So anytime we use StructureMap to construct an instance of a type that has a dependency on IPostRepository, StructureMap will pass in an instance of InMemoryPostRepository.

Well if that’s true, we better then create that class. Normally, I would use a SqlPostRepository. But for purposes of this demo, we’ll store blog posts in memory using a static collection. We can always implement the SQL version later.

Note: This is where I would normally write tests for InMemoryPostRepository but this post is already long enough, right? Don’t worry, I included unit tests in the downloadable code sample.

public class InMemoryPostRepository : IPostRepository
{
  //simulates database storage
  private static IList<Post> posts = new List<Post>();

  public void Create(Post post)
  {
    posts.Add(post);
  }

  public System.Collections.Generic.IList<Post> 
    ListRecentPosts(int retrievalCount)
  {
    if (retrievalCount < 0)
      throw new ArgumentOutOfRangeException("retrievalCount"
          , "Let’s be positive, ok?");

    IList<Post> recent = new List<Post>();
    int recentIndex = posts.Count - 1;
    for (int i = 0; i < retrievalCount; i++)
    {
      if (recentIndex < 0)
        break;
      recent.Add(posts[recentIndex--]);
    }
    return recent;
  }

  public static void Clear()
  {
    posts.Clear();
  }
}

Quick, We Need A Factory {.clear}

We’re almost done. We now need to hook up StructureMap to ASP.NET MVC by writing implementing IControllerFactory. The controller factory is responsible for creating controller instances. We can replace the built in logic with our own factory.

public class StructureMapControllerFactory : DefaultControllerFactory
{
  protected override 
    IController CreateController(RequestContext requestContext, string controllerName) 
  {
    try
    {
      string key = controllerName.ToLowerInvariant();
      return ObjectFactory.GetNamedInstance<IController>(key);
    }
    catch (StructureMapException)
    {
      //Use the default logic.
      return base.CreateController(requestContext, controllerName);
    }
  }
}

Finally, we wire it all up together by adding the following method call within the Application_Start method in Global.asax.cs.

protected void Application_Start() {
  ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());

  RegisterRoutes(RouteTable.Routes);
}

And we’re done! Now that we have hooked up the dependency injection framework into our application, we can revisit our site in the browser (after compiling) and we get…

View Not Found
Message

Excellent! Despite the Yellow Screen of Death here, this is a good sign. We know our dependency is getting injected because this is a different error message than we were getting before. This one in particular is informing us that we haven’t created a view for this action. So we need to create a view.

Sorry! Out of scope. Not in the spec.

I leave it as an exercise for the reader to create a view for the page, or you can look at the silly simple one included in the source download.

Although this example was a ridiculously simple application, the principle applies in building a larger app. Just take the techniques here and rinse, recycle, repeat your way to TDD nirvana.

To see the result of all this, download the source code.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

50 responses

  1. Avatar for Evan
    Evan December 7th, 2007

    You rock! ;-)

  2. Avatar for Jeffrey Palermo
    Jeffrey Palermo December 7th, 2007

    @Phil,
    The first item to get committed to the trunk of mvccontrib was a StructureMapControllerFactory.
    You can check it out here:http://www.codeplex.com/MVC...
    We're going to go public and advertise more once we can build against the public CTP. Then it will make more sense for the public to use it.

  3. Avatar for Fredrik Norm&#233;n
    Fredrik Norm&#233;n December 7th, 2007

    Your blog post is so much nicer than mine ;)
    Something that I don’t like is that the ControllerFactory will get the Type of the Controller. You need here as with Spring.Net use the Type.Name to get the name and let another framework once again locate the type and then create an instance of the controller. I think it’s the ControllerFactory’s responsibility to locate the Controller and that you should make sure to pass the name of the controller as the argument to the factory, not the type.

  4. Avatar for Haacked
    Haacked December 7th, 2007

    @Fredrik - Yes, I saw your comment in Connect. I thought I responded to it. We'll change that in the next milestone. Thanks for submitting the feedback! :)

  5. Avatar for DotNetKicks.com
    DotNetKicks.com December 7th, 2007

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  6. Avatar for Jeremy D. Miller
    Jeremy D. Miller December 7th, 2007

    Cool post, says the horribly biased guy.
    Just so folks with angle bracket allergies know, you don't have to use Xml configuration for the simple use cases with StructureMap anymore:
    http://codebetter.com/blogs...

  7. Avatar for ScottGu's Blog
    ScottGu's Blog December 8th, 2007

    Here is the latest in my link-listing series .&amp;#160; Also check out my ASP.NET Tips, Tricks and Tutorials

  8. Avatar for Sean Chambers
    Sean Chambers December 8th, 2007

    Excellent stuff Phil!
    I am definately looking forward to this. Even though I am very biased and love monorail. I think you guys have finally hit the nail on the head this time. Couple this with the fact that you are now at MS, I think this will be very good! =)
    The only thing I really don't like, and I'm sure you've heard this already, is the fact that every action requires a [ControllerAction] attribute. IMO, this is a lot of extra typing that isn't necessarily needed. I know you guys are trying to help out by making sure the developer knows what exactly they are exposing, but education would be more powerful here than requiring a specific attribute on every method. Just my 2 cents tho!
    Is there anyway that we can make it so any public methods are automatically set as actions in a configuration or something along those lines?
    Also, is there a way to set values to send back to the view in an array rather than passing them to RenderView? Like PropertyBag[] in MonoRail?
    Other then that everything looks pretty good! Great Job!! Looking forward to the CTP

  9. Avatar for Sean Chambers
    Sean Chambers December 8th, 2007

    Phil Haack has a tutorial type post of usage of the new MS MVC with TDD, DI and the Repository Pattern

  10. Avatar for Haacked
    Haacked December 8th, 2007

    @Sean - thanks for the feedback. Yep, I've heard a lot about the [ControllerAction] attribute from some people. Rather than attempt to address it everytime it comes up, I'll write a blog post that addresses that single item.
    Keep in mind though, we'd love to hear feedback on other areas of the framework. It seems that one thing gets a disproportionate amount of attention. I have to say, if that's the only thing we get "wrong", then I'm happy. But I would bet there are bigger things we missed and I hope to hear feedback on them when the CTP is released.

  11. Avatar for Javier Lozano
    Javier Lozano December 8th, 2007

    Phil, great post! I've always liked your style of writing. You're very good at taking abstract concepts and explain them in terms people can relate to.
    This is a great asset for people trying to grok the benefits of using ASP.NET MVC!

  12. Avatar for Christopher Steen
    Christopher Steen December 8th, 2007

    ASP.NET TDD and Dependency Injection with ASP.NET MVC [Via: Haacked ] Link Blogs Silverlight Cream...

  13. Avatar for Tony Testa's World
    Tony Testa's World December 8th, 2007

    ASP.NET MVC Framework (Delayed)

  14. Avatar for ScottGu's Blog
    ScottGu's Blog December 9th, 2007

    Earlier today we released the first CTP preview of an &amp;quot;ASP.NET 3.5 Extensions&amp;quot; release that

  15. Avatar for Marlon Grech
    Marlon Grech December 9th, 2007

    This is totally cool... You are the BEST!!!!!

  16. Avatar for Maor David
    Maor David December 9th, 2007

    The ASP.NET 3.5 Extensions Preview is a preview of new functionality being added to ASP.NET 3.5 and ADO

  17. Avatar for Javier-Romero
    Javier-Romero December 9th, 2007

    ASP.NET 3.5 Extensions CTP Preview Lanzado ...

  18. Avatar for Eilon Lipton's Blog
    Eilon Lipton's Blog December 10th, 2007

    This week the first preview of the ASP.NET MVC framework was released to the web as part of the ASP.NET

  19. Avatar for di .NET e di altre Amenit
    di .NET e di altre Amenit December 11th, 2007

    ASP.NET 3.5: Un po' di link alla rinfusa #4

  20. Avatar for Matt Blodgett
    Matt Blodgett December 11th, 2007

    As a neophyte interested in unit testing and dependency injection, I have to admit that I'm really taken aback by the amount of _stuff_ you had to write to get this simple bit of functionality set up.
    I'm struggling to understand how it could possibly be worth it. Would someone please enlighten me?

  21. Avatar for Haacked
    Haacked December 11th, 2007

    @Matt You should search my blog for TDD and you'll see I've written extensively about the benefits of TDD.
    AS for this example, I was taking an extremely detailed "first-principles" style approach. So in the real-world, the code would be much less in the test by employing helper methods and the like.
    Also, some of the extra verbosity may be due to issues in the ASP.NET MVC design we plan to improve.

  22. Avatar for StevenHarman.net
    StevenHarman.net December 12th, 2007

    TDD DI ASP.NET MVC Made Better with StructureMap's Fluent API, Oh My!

  23. Avatar for nibblers revenge
    nibblers revenge December 18th, 2007

    ASP.NET 3.5 Extensions CTP Preview Released

  24. Avatar for Developer Blogs
    Developer Blogs December 20th, 2007

    Earlier today we released the first CTP preview of an &amp;quot;ASP.NET 3.5 Extensions&amp;quot; release that

  25. Avatar for My World
    My World January 3rd, 2008

    Ok, so I just posted less than an hour ago, but now I've found something worth talking about. :) After

  26. Avatar for Omid Zaman
    Omid Zaman January 6th, 2008

    ASP.NET MVC Is Available (CTP)

  27. Avatar for ASP.NET Chinese Blogs
    ASP.NET Chinese Blogs January 17th, 2008

    【原文地址】 ASP.NET 3.5 Extensions CTP Preview Released 【原文发表日期】 Sunday, December 09, 2007 8:55 PM 今天早些时候

  28. Avatar for Basharat Hussain
    Basharat Hussain January 20th, 2008

    Hi,
    I could not compile the sample. I have following errors in config files. Please help me in this regard.
    In StructureMap.config file - <StructureMap> says element is not declared
    In Web.Config file - <dynamicData attribute gives following error "the element 'system.web.extensions' has invalid child dynamicData, List of possible elements expected: 'Scripting'"
    Please guide me to solve these issues. thanks.
    BR/Bash

  29. Avatar for Noticias externas
    Noticias externas January 22nd, 2008

    Nella prima parte del post ho introdotto il nuovo ASP.NET MVC Framework fino all&amp;#39;implementazione

  30. Avatar for CodeClimber
    CodeClimber January 28th, 2008

    ASP.NET MVC Link collection

  31. Avatar for Nick Berardi
    Nick Berardi July 25th, 2008

    Thanks for the source, I have just got started on TDD and basically the Alt.NET way of doing things. So I am hoping this will help me move in the right direction.

  32. Avatar for Praveen Angyan
    Praveen Angyan August 25th, 2008

    So, I finally get it. It all snapped into place: DI, Mocking, using Interfaces for the parts of the code that we want to decouple etc. I've been rereading this post and others for the past two weeks and I suddenly got it and started using it in my production code.
    However there is one crucial point I'm missing here in this method: BlogControllerPassesCorrectViewData
    Isn't the whole point of writing an InMemoryPostRepository class to be able to use it in the unit tests, more specifically in BlogControllerPassesCorrectViewData in your case? This would get rid of a whole lot of code required for mocking, the tests would still run as fast. What do you lose by coupling your unit test to a lightweight repository instance?
    This really came up because when I tested an action that takes values from an HTML form and creates a new entry in the repository and I used your patterns, I had a whole lot of code to mock the different instances. And in the end I couldn't even test a crucial bit of functionality.

  33. Avatar for Shay Jacoby
    Shay Jacoby October 12th, 2008

    Hi, Thanks for the article.
    I think that your StructureMapControllerFactory class is not a good idea because it generates exception (doesn't matter if You put try/catch) on every unmapped controller.

  34. Avatar for serhat
    serhat December 2nd, 2008

    How about if I go like this:
    private IPostRepository repository;
    BlogController()
    {
    this.repository = new InMemoryPostRepository();
    /* or new RepositoryFactory().GetRepository(SomeResource.DefaultRepositoryName); */
    }
    BlogController(IPostRepository repository)
    {
    this.repository = repository;
    }
    And use the latter constructor when testing, so I do not need to use StructureMap and do not bother writing config files?

  35. Avatar for Ben Norman
    Ben Norman December 4th, 2008

    I have not been able to move your sample to StructureMap 2.5. The DataContext is not able to find the ConnectionString. What are the chances of another 20 minutes on StructureMap 2.5 and if possible without a config file.

  36. Avatar for Marko
    Marko January 26th, 2009

    Wow!
    Great post :)

  37. Avatar for Jei
    Jei February 9th, 2009

    Hi Phil,
    I have been keenly following the use of StructureMap as an IOC container for Dependency Injection. I have looked at illustrations by Jeremy Miller and Rob Connery among others and I get expect results when I do the injection from code but not when I try to use StructureMap.config. For instance, with your sample here, an exception is thrown at the line:
    return ObjectFactory.GetNamedInstance<IController>(key);
    in StructureMapControllerFactory class. The following are the exception details:
    StructureMap configuration failures:
    Error: 210
    Source:
    The designated default instance 'InMemory' for PluginType MvcApplication.Models.IPostRepository, MvcExample1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null cannot be found.
    am using StructureMap Version 2.5.3 (I don't know whether this might be the problem)
    ... Sorry for reviving this blog.
    Best Regards,
    Jei.

  38. Avatar for Dsmacks
    Dsmacks May 2nd, 2010

    Great post, easy to read and follow! However the download source code link isn't working.

  39. Avatar for Tombo
    Tombo June 27th, 2011

    Can't seem to get the download to work! :\

  40. Avatar for Vivien Adnot
    Vivien Adnot August 11th, 2011

    Hi Phil,
    Your article is excellent but the download link doesn't work.
    I've read a bit of StructureMap documentation and I found these
    ObjectFactory.Initialize(x =>
    {
    x.ForRequestedType<IRepository>().Use<Repository>()
    .WithCtorArg("connectionString").EqualTo("a connection string");

    // Or, since it's smelly to embed a connection string directly into code,
    // we could pull the connection string from the AppSettings
    x.ForRequestedType<IRepository>().Use<Repository>()
    .WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
    });

    var repository = ObjectFactory.GetInstance<IRepository>();
    This example seems pretty great too, it seems that the ugly xml file isn't necessary anymore. Do you agreee with that ?

  41. Avatar for Don Rolling
    Don Rolling January 13th, 2012

    However you might feel about TDD, love it or hate it, you have to admit that it's a lot of work to setup.
    The funny thing is that it doesn't keep errors from occurring.
    The funnier thing is that the link to the code download on this site is currently broken and I can't download it.
    I guess you should have written a test that Asserts that your links are valid. :)

  42. Avatar for DSmith
    DSmith February 16th, 2012

    I'm still not sold on TDD. I guess I come from a much older school of - if you don't know exactly what each line of code will do to your app in every place then don't write it. A programmer should be able to write code in notepad, no debugger or background compiler and know exactly what they are doing. If you are relying on testing every line of code you write then you don't know what you're doing.

  43. Avatar for Chinthana
    Chinthana May 24th, 2012

    I agree with DSmith's some of the comments, but I don't think TDD is anything about "Awareness of the developer". The thing is actually when you hand over your code to someone else, and doing enhancement (may be a stable code), might lead to crash your code. If you had written test cases then that would have been prevented at the time of you do changes and compile your test library. TDD is really valuable
    when it comes to complex business logic (which does not throw run time application errors, but logic errors)

  44. Avatar for Khandokar Sabbir Ahmed
    Khandokar Sabbir Ahmed December 3rd, 2012

    That's a great post.You have shown repository pattern also.Can you tell me if your repository pattern is generic.What will be the PluginFamily and Plugin in StructureMap.Config file.

  45. Avatar for gungun
    gungun February 24th, 2013

    This is great article. I learnt so much from it.
    When trying to download source code link, got following message
    Sorry, that page you requested cannot be found. If the page does not show up within 24 hours, you can file a missing page report.

  46. Avatar for vijay
    vijay March 11th, 2013

    source code not found

  47. Avatar for Pete
    Pete June 4th, 2013

    The download link is broken, any chance for a fix?

  48. Avatar for sinaj
    sinaj June 18th, 2013

    Not able to download the source code

  49. Avatar for user
    user September 22nd, 2014

    testing

  50. Avatar for Souvik Mitra
    Souvik Mitra December 18th, 2017

    If we are using the multi layer project with DI, then how can I implement TDD using Mock?