English 中文(简体)
Test-driven development with ASP.NET MVC - where to begin?
原标题:

I ve read a lot about Test-Driven Development (TDD) and I find the principles very compelling, based on personal experience.

At the moment I m developing a website for a start-up project I m involved in, and I d like to try my hand at putting TDD into practice.

So ... I create a blank solution in Visual Studio 2010, add an ASP.NET MVC Website project and a test project.

I also add a class library called Domain , for my domain objects, and a test project for that.

Now I m wondering where to begin. Should I be writing a test before I do anything right? The question is - should I start writing tests for domain objects? If so, what exactly should I be testing for, since the domain objects don t yet exist?

Or should I be starting with the Website project and writing tests for that? If so, what should I write a test for? The Home controller / Index action?

最佳回答

I typically start by collecting a set of stories for the application I m going to develop. From that I generate a domain model, usually on "paper". I organize the stories that I m going to implement and start creating the domain model in the DB for the first set of stories.

Once I have the initial DB, then I use an ORM, in my case, LINQ to SQL, to map the DB tables onto a set of initial classes. I don t typically unit test generated code so this gives me a fair amount of code as a base to start with. I then create a stub method, which throws a not implemented exception, to implement one feature of the first domain class I m working with. Typically, I start with validation logic. Once you have your stub method, then you can use the VS right click menus to create one or more unit tests for that method. Then you re on your way.

Once I ve finished with the domain objects for the first story, I then start working with the MVC aspects. First, I ll create the view models for the first view. These are typically just an empty container class as this point. Then I ll create the view and strongly type it to the view model. I ll start fleshing out the view, adding properties to the view model as needed by the view. Note that since the view model is simply a container there aren t typically unit tests associated with it. It will however be used in subsequent controller tests.

Once the view is complete (or at least my initial concept is complete), I then create the stub controller action or actions for it, again the stub method simply throws a not implemented exception. This is enough to get it to compile and let me use the tools to create unit tests for it. I proceed as needed to test the method(s) and ensure that it acts appropriately to the given inputs and produces an appropriate view model. If the method can produce multiple view models, i.e., render multiple views I may iterate over the process of creating view models/views/controller code until the story or stories are complete.

Repeat as necessary until your set of stories are implemented, refactoring along the way.

问题回答

Writing unit tests before even declaring the class you are testing seems a little extreme in a static languages such as C#. So you start by declaring your domain classes, throw a few interfaces that define operations you will perform on these domain objects and then you add a class that will implement an interface, leaving methods just throw NotImplementedException. At that moment you could write a unit test for this class, as all the types are known. You run the test which will fail, then you implement the method and run the test again - it will pass. Then you could refactor and optimize your implementation, your unit test should still pass.

Once you have a nice domain model and data access layer you could move to the web project where you create controllers, using the interfaces you previously defined (by making a constructor that takes this interface). You write a unit test for this controller by replacing the interface with a mock object, so that you can test the controller actions in isolation from your data access code.

And most importantly: don t be afraid to add classes and interfaces. I ve seen people write huge methods that perform multiple things at the same time and which are difficult to test. Try isolating different tasks into methods that you could easily write specifications for: what output you expect for the different possible inputs.

For a long answer you should take small steps like this.

1)-First write a failing test

    [Test]
    public void AddSameTag()
    {
        UserMovie userMovie = new UserMovie();

        userMovie.AddTag("action", "dts", "dts");
        Assert.AreEqual(2, userMovie.Tags.Count);
    }

2)- Write simplest code to pass the test.

public virtual void AddTag(params string[] tags)
    {
        foreach (var text in tags)
        {
            Tag tag =new Tag(text.Trim());
            if (!movieTags.Contains(tag))
                movieTags.Add(tag);
        }
    }

3)- Refactor

. For ASP.NET MVC and TDD starter you can ignore Controller Test and focus on Domain by TDD.





相关问题
WebForms and ASP.NET MVC co-existence

I am trying to make a WebForms project and ASP.NET MVC per this question. One of the things I ve done to make that happen is that I added a namespaces node to the WebForms web.config: <pages ...

Post back complex object from client side

I m using ASP.NET MVC and Entity Framework. I m going to pass a complex entity to the client side and allow the user to modify it, and post it back to the controller. But I don t know how to do that ...

Create an incremental placeholder in NHaml

What I want to reach is a way to add a script and style placeholder in my master. They will include my initial site.css and jquery.js files. Each haml page or partial can then add their own required ...

asp.net mvc automapper parsing

let s say we have something like this public class Person { public string Name {get; set;} public Country Country {get; set;} } public class PersonViewModel { public Person Person {get; ...

structureMap mocks stub help

I have an BLL that does validation on user input then inserts a parent(PorEO) and then inserts children(PorBoxEO). So there are two calls to the same InsertJCDC. One like this=>InsertJCDC(fakePor)...

ASP.NET MVC: How should it work with subversion?

So, I have an asp.net mvc app that is being worked on by multiple developers in differing capacities. This is our first time working on a mvc app and my first time working with .NET. Our app does not ...

System.Web.Mvc.Controller Initialize

i have the following base controller... public class BaseController : Controller { protected override void Initialize(System.Web.Routing.RequestContext requestContext) { if (...

热门标签