views:

104

answers:

8

I have just started to learn ASP.NET MVC. When comparing ASP.NET MVC with Web Forms one of the main advantage of MVC is always told to be better support of Unit Testing. Can I got a good explanation of how it has better support?

Edit : If possible please provide example in both.

+3  A: 

Because you can create a controller object in your unit test, call some actions on it, and see the result right away, then you can Assert.IsBlahBlahBlah(); on it.

For example,

    [TestMethod]
    public void Index()
    {
        // Arrange
        HomeController controller = new HomeController();

        // Act
        ViewResult result = controller.Index() as ViewResult;

        Assert.IsNotNull(result);
    }

With that method, you now know that your Index view is returned from the Home controller.

Nate Bross
A: 

It's far more cumbersome to test a code behind page than to test a controller. With the MVC pattern, there's a more logical separation of presentation logic thus making it easier to write tests.

jamesaharvey
+4  A: 

The ASP.NET page lifecycle makes it incredibly difficult to unit test classes that derive from Page, which starts out with too many responsibilities and becomes a god object when you add application logic to it. Even worse, it has hidden dependencies on static classes and requires a default parameterless constructor, which limits your ability to inject dependencies.

So, to make an ASP.NET WebForms page testable, you need to take all the logic out of your code-behinds and put it in another class - typically a Presenter as in the Model-View-Presenter pattern.

ASP.NET MVC controllers are already separated from their templates and aren't encumbered by the ASP.NET page lifecycle.

Jeff Sternal
+5  A: 

Asp.Net MVC has better unit testing support for one main reason - the whole architecture is built to use HttpContextBase, HttpRequestBase and HttpResponseBase.

Asp.Net webforms is dependent on HttpContext.Current, which is a singleton that you have no control over - it is set up and passed to your pages as part of the HttpApplication executing the request. In most cases, in order to get the page to execute correctly, you need to execute it in a real HttpContext. Since many of the properties of HttpContext are not settable (like Request and Response), it is extremely difficult to construct fake requests to send to your page objects.

This makes unit testing webforms pages a nightmare, since it couples all your tests to needing all kinds of context setup.

Contrast that to ASP.Net MVC, where you can mock an HttpContext! Now your code doesn't even need a web server to give it context, you can just set up the bits you need, and hand the mocked context to your method.

womp
+1  A: 

You can do exactly the same thing with Web Forms, it's just that people who don't know better write code that can't be tested this way.

There's no reason to have business logic in a codebehind class. Same with data access logic. Even right there, that lets you test the parts of the application most subject to both bugs and testing.

Some might say that doesn't allow you to test for button clicks and other user-interface events. If you want to do that, then you can go ahead and create your own MVC or MVP or other such pattern, that does use a separate interface for the user interface actions. Then do exactly the same kind of test you'd do if using ASP.NET MVC.

And you still have the problem of not being able to test client-side code.

John Saunders
True, although having a built in way to test redirects without using a layer of abstraction is definitely a plus
Richard Szalay
@Richard: yeah, I suppose testing redirects is nice - but do you do tests like that in a _unit_ test? I suppose if you're using TDD, you have to.
John Saunders
+1  A: 

If you want to use ASP.Net WebForms (like i do) and unit tests together, take a look at this:

WebForms MVP on codeplex

Works for me.

Flynn
A: 

Slightly OT but you may want to look at Selenium for Unit Testing webpages....

Lawrence Tierney
A: 

In reference to Lawrences suggestion about Selenium, there is also WatiN.

This is not specific to MVC, but I think MVC definitely helps in that it keeps element ids and classes clean and easier to target from the test.

With WatiN you can do the following (example from their site).

[Test]
public void SearchForWatiNOnGoogle()
{
 using (var browser = new IE("http://www.google.com"))
 {
  browser.TextField(Find.ByName("q")).TypeText("WatiN");
  browser.Button(Find.ByName("btnG")).Click();

  Assert.IsTrue(browser.ContainsText("WatiN"));
 }
}
Matt