This is an archive of blog posts from a "long time ago". If you find this useful, let me know and I'll revive it.

code blog foo - tag line bar

Dynamic ASP.NET MVC - Part 3, Your First Failing Test

Listing All Blog Posts

For a blog, we need to well..list all blog posts. Currently we have one Controller action on HomeController.cs that returns Index.cshtml:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

    }

This implementation is incomplete. The view (Index.cshtml) needs to be given a list of blog titles to display. Let's write a test stating that the ViewBag.Blogs needs to be populated with an IEnumerable<dynamic>.

Dealing With Anonymous Types Across Projects

Note: you only have to do this if you didn't use the warmup command in the previous blog post to bootstrap your application. If you've done so, then just skim through this section.

So here's the thing...anonymous types are by default declared as internal classes. There will be points in time where we'll need to perform assertions on anonymous types. We need to ensure that anonymous types declared are visible outside of their respective projects, here's how we do that:

First Failing Test (written in NSpec)

We'll be using NSpec to write our tests (the installation was covered in Part 2). Visit the NSpec website if you need a crash course on it (you don't need to know all the in's and out's of the framework to start using it). Here are the steps:

//describe_HomeController inherits from nspec
//access modifier for class isn't required
class describe_HomeController : nspec
{
    //declare controller as a private member variable on class
    HomeController controller;
    //view result property will get set within our tests
    ViewResult viewResult;
    //view bag will get set within our tests
    dynamic viewBag;
       
    //nspec will run this method before each test
    void before_each()
    {
        controller = new HomeController();
    }

    //define a "method level context" called "when navigating to the home page"
    void when_navigating_to_the_home_page()
    {
        //this "act" is directly related to the context...
        //it navigates to the home page and sets the view result and view bag
        act = () =>
        {
            viewResult = controller.Index() as ViewResult;
            viewBag = viewResult.ViewBag;
        };

        //perform your assertion stating that the view bag should have
        //a property called Blogs that is a enumerable of dynamic
        it["gives a list of blogs"] = () =>
            (viewBag.Blogs as IEnumerable<dynamic>).should_not_be_null();
    }
}

Saving the describe_HomeController.cs file will fire off specwatchr, which will run the test for you...growl will notify you that you have a failing test (you can look at the console output in the Ruby Command Prompt for additional details).

Make it Pass

Updating the controller like so will make our test pass (it's important to do the simplest thing possible to make the tests pass...doing this will ensure that our test suite is thoroughly specified):

public class HomeController : Controller
{
    public ActionResult Index()
    {
        //this line will make our test pass
        ViewBag.Blogs = new List<dynamic>();

        return View();
    }
}

Saving the HomeController.cs file will fire off specwatchr, which will run impacted tests for you...growl will notify you that all your tests pass (you can look at the console output in the Ruby Command Prompt for additional details).

Flushing Out the Rest of the Implementation

This is not a complete implementation. Looks like we need to expand our test suite. We need to communicate that the blog posts come from some model class. We are going to use a slightly altered version of Massive (which was included in the oak NuGet package). There are a few things we need to do before we can write our next test (appeasing the compiler).

Take it All in

We covered our first controller test. As it stands, if you try to start the website, you'll probably get some exceptions (the next parts of this series will explain why and we will fix those things...so don't worry). If Moq didn't make sense, then take some time to read this blog post on Moq and Behavior Driven Development. The important thing to take away from Part 3 is the evolution of the implementation and how we didn't have to press an debug buttons, build buttons, or test buttons (those pieces were handled for us so we could concentrate 100% on the tests and implementation).

A Dialog With Myself

Wait just a second. This "first failing tests" is pretty stupid. Your use of Moq gives us very little value. All you are doing is asserting that the All() method on the Blogs model has been called.

You are absolutely right. The first failing test we created is absolutely useless as it stands, and I wouldn't write this test in the "real world". We are going to elaborate on this test in the next part. I wanted you to get used to the development flow before I open the flood gates.

It also looks like that we are prematurely mocking. Why immediately introduce dependency injection and mocking?

Same reason as above. We as developers have the habit of mocking too much, this is post is a clear example of how silly this is. Also, I wanted Part 3 to be about the development flow and get you used to the rhythm. We are actually going to back out the dependency injection and the mocking in Part 4.


Written: 6/18/2011