Getting started with testing an ASP.NET Webforms Application (MVP Pattern)

0 comments
In this article we explore how unit tests are created in an ASP.NET WebForms Application. Although there are sections that are specific to the MVP pattern, there are also a few tips and guidelines about Unit Testing of a Web Application in general.

The purpose of this article is to explain how to test an ASP.NET Webforms Applications. How the Model-View-Presenter pattern is helping us in that, how do we use mock-up libraries to simulate objects like HttpContext and how do we use Visual Studio 2010 Testing Environment.

Testing Web Applications

First of all, when we want to test a Web Application we are considering two types of tests. Acceptance Tests and Unit Tests.

Acceptance Tests

Acceptance Tests are tests from a user prospective and most of the times an automated-browser testing tool is used (like WatiN, Selenium etc.) So we are testing the user experience, if our app works in different browsers, if client-validation works as it should etc.

Unit Tests

Unit Tests are tests dedicated to test our code, our business logic and validation, our database interaction and everything that are not related to how data is displayed. Although many times Unit Tests and Acceptance Test may have overlapping areas (example, when testing if a page works simultaneously validation is also being tested) it's important to have both in a project.
For now, let's focus on Unit Tests.

Example

Let's consider the following real world but simple example:
Almost every website has a contact page. The user enters his details and sends them to the server. The server processes the data and informs the user about the result. How can we test a page like this?

Figure 1: Screenshot - Contact Page

Screenshot - Contact Page

Explaining the MVP Pattern

The MVP pattern stands for Model-View-Presenter and doesn't differ a lot from MVC (Model-View-Controller). When an application is developed using the MVP pattern it's more testable because layers are being separated from each other. So each layer's responsibility is clearer thus easier to define test cases to run against. An excellent open-source framework that helps us build a WebForms application using the MVP Pattern is WebFormsMVP. This framework is being used in this example.
An implementation of the page above using the MVP Pattern along with a brief explanation of the pattern its self would be the following.

Model

Model is the class that holds the data of our page. In this case it is a simple class with three properties that are represented by our text fields and one property that holds if the Model is persisted or not to our database.

Listing 1: ContactModel.cs

1.public class ContactModel
2.{
3.    public string Name { get; set; }
4.    public string Message { get; set; }
5.    public enProcessState ProcessState { get; set; }        
6.    public string Email { get; set; }
7.}
It's also included just for reference the enProcessState enum.

Listing 2: enProcessState.cs

1.public enum enProcessState
2.{
3.    Pending,
4.    Saved
5.}

View

View, in this case, is the user control that displays the form and defines events – if necessary – that correspond to user actions. Because a view can be implemented in various ways an interface is being defined and the user control is implementing that interface.

Listing 3: IContactView.cs

01.public interface IContactView : IView<ContactModel>
02.{
03.    event EventHandler<ContactEventArgs> Contacting;
04.}
05.public class ContactEventArgs : EventArgs
06.{
07.    public string Name { get; set; }
08.    public string Email { get; set; }
09.    public string Message { get; set; }
10.}
The implementation of the interface is our user control.

Listing 4: ContactControl.ascx

01.<asp:MultiView runat="server" ID="mv" ActiveViewIndex="0">
02.    <asp:View runat="server" ID="vContact">
03.        <fieldset>
04.            <legend>Contact Us</legend>
05.            <table>
06.                <tr>
07.                    <td
08.                        Name
09.                    </td>
10.                    <td>
11.                        <asp:TextBox runat="server" ID="txtName" />
12.                        <asp:RequiredFieldValidator ErrorMessage="*" ControlToValidate="txtName" runat="server" />
13.                    </td>
14.                </tr>
15.                <tr>
16.                    <td>
17.                        Email
18.                    </td>
19.                    <td>
20.                        <asp:TextBox runat="server" ID="txtEmail" />
21.                    </td>
22.                </tr>
23.                <tr>
24.                    <td>
25.                        Message
26.                    </td>
27.                    <td>
28.                        <asp:TextBox runat="server" ID="txtMessage" TextMode="MultiLine" Rows="10" />
29.                    </td>
30.                </tr>
31.                <tr>
32.                    <td colspan="2">
33.                        <asp:Button Text="Contact Us" runat="server" OnClick="btnContactUs_Click" />
34.                    </td>
35.                </tr>
36.            </table>
37.        </fieldset>
38.    </asp:View>
39.    <asp:View runat="server" ID="vSaved">
40.        Contact request was Saved! <a href="ContactList.aspx">View all</a> contact requests.
41.    </asp:View>
42.</asp:MultiView>
And our code-behind is the following.

Listing 5: ContactControl.ascx.cs

01.public partial class ContactControl : MvpUserControl<ContactModel>, IContactView
02.{
03.    public event EventHandler<ContactEventArgs> Contacting;
04.    private void OnContacting(ContactEventArgs args)
05.    {
06.        if (Contacting != null)
07.            Contacting(this, args);
08.    }
09.    protected void btnContactUs_Click(object sender, EventArgs e)
10.    {
11.        ContactEventArgs args = new ContactEventArgs();
12.        args.Name = txtName.Text;
13.        args.Email = txtEmail.Text;
14.        args.Message = txtMessage.Text;
15.        OnContacting(args);
16.        View activeView = Model.ProcessState == enProcessState.Saved ? vSaved : vContact;
17.        mv.SetActiveView(activeView);
18.    }
19.}
 
READ MORE>>

0 comments: