views:

72

answers:

2

I have a simple page with a Grid that I'm binding a collection of objects to. I also have some simple functionality on the grid to edit and save rows. I would like to write unit tests for this page, but it's not really making sense to me.

For example:

Private Sub LoadGrid()
'Populate Collection
grid.datasource = MyCollection
grid.databind()
end sub

I guess a Sub really doesn't need a unit test, but what if this were a function that returned true when the grid had been loaded. How do you write a unit test for this? What other test should be done on a simple web page like this?

As always, thanks to everyone who give any sort of input.

+2  A: 

How do you write a unit test for this?

The first step is actually making your form testable. Have a look at this page for separating UI and BL layers, there are about a bajillion different ways to implement MVC, MVP, and all of its variants, and there's no One True Way™ to do it. So long as your code is sane and consistent, other people will be able to work on your code.

I personally find the following pattern works in most cases for testing UIs:

  • Create an interface representing your Model.
  • Create a class for your controller which handles all the updates to the model.
  • Your view should listen to changes to the model.

So in the end, you end up with something like this (sorry, my VB-fu is rusty, writing this in C# instead):

interface IProductPageModel
{
    int CurrentPage { get; set; }
    int ItemsPerPage { get; set; }
    DataSet ProductDataSet { get; set; }
}

class ProductPageController
{
    public readonly IProductPageModel Model;
    public ProductPageController(IProductPageModel model)
    {
        this.Model = model;
    }

    public void NavigateTo(int page)
    {
        if (page <= 0)
            throw new ArgumentOutOfRangeException("page should be greater than 0");

        Model.CurrentPage = page;
        Model.ProductDataSet = // some call to retrieve next page of data
    }

    // ...
}

This is concept code, of course, but you can see how its very easy to unit test. In principle, you could re-use the same controller code in for desktop apps, silverlight, etc since your controller doesn't depend directly on any particular view implementation.

And finally on your form side, you'd implement your page similar to:

public class ProductPage : Page, IProductPageModel
{
    ProductPageController controller;

    public ProductPage()
    {
        controller = new ProductPageController(this);
    }

    public DataSet ProductDataSet
    {
        get { return (DataSet)myGrid.DataSource; }
        set { myGrid.DataSource = value; myGrid.DataBind(); }
    }

    protected void NavigateButton_OnCommand(object sender, CommandEventArgs e)
    {
        controller.NavigateTo(Convert.ToInt32(e.CommandArgument));
    }
}

Here there's no real distinction between view and model -- they're the same entity. The idea is to make your code-behind as "stupid" as possible, so that as much testable business logic is contained in the controller as possible.

What other test should be done on a simple webpage like this?

You'd want tests for any sort of form validation, you want to make sure you're throwing exceptions in exceptional cases, ensuring that your controller methods update your model in an expected way, and so on.

Juliet
+1  A: 

Juliet is right.

The line of code where you said

'Populate Collection

that is the testable part. You can do assertions on if the collection is null, if it has items, if it has exactly 42 items. But that would be an integration test.

If you can isolate all the calls to the database (the part that returns a datareader), then return a empty, fake DbDataReader, then you can test everything inbetween the UI and the database.

Tests that spin up a browser and verify that a table is render, similarly is a integration test that will depend on having IIS up and working (and a DB up and working, unless you have a repository you can fake)

If you are just getting started, I would look for all the easy to test code first, such as methods that do have dependencies on the database, then move on the tricker tests that require mocking/stubbing/faking database servers, etc.

MatthewMartin