Skip navigation

Exploring NUnitASP

Powerful Open Source Unit Testing

CoverStory

LANGUAGES: VB.NET

ASP.NET VERSIONS: 1.x

 

Exploring NUnitASP

Powerful Open Source Unit Testing

 

By Rob Walling

 

Test Driven Development (TDD) is a growing trend in the software industry. In the past year, a multitude of articles have been published touting the benefits of the test-driven approach. While the benefits of TDD over a more traditional, code-first approach are still being debated, it s safe to say that automated unit testing has become a widely accepted practice. Being able to test the basic features of an application with a single button-click is simply too appealing to ignore.

 

This article, however, does not discuss TDD specifically, because the topic was well covered by Ian Blackburn in his article Test Driven Development with ASP.NET. Rather, this article serves as further exploration of NUnitAsp, an open source tool commonly used in TDD, but equally relevant to code-first methodologies (see Ken McNamee s introduction to NUnitASP).

 

Testing Web-based user interfaces is often done manually, which ultimately means a lot of time-intensive pointing and clicking. There are automated UI test tools available, but most have prices well beyond the reach of today s tight IT budgets. One alternative, NUnitAsp, extends the well-known open source unit testing framework NUnit to allow for scripted testing of ASP.NET user interfaces. Using the .NET language of your choice, you can easily create scripts that programmatically input data and click the buttons of your Web pages.

 

Overview

NUnit is an open source unit testing framework written in C#, and ported from the Java-based framework JUnit. If you ve read any of the recent articles on Test Driven Development, you re probably familiar with this tool. NUnit allows .NET developers to create methods, known as tests, which call production code, feeding the appropriate parameters and asserting the proper results are returned. These tests are contained within Test Fixtures, which are nothing more than .NET classes.

 

NUnit is commonly used to perform unit testing on the business and data tiers, but because of the complexity of the environment, it is unable to perform tests directly on ASP.NET code. The solution is NUnitAsp, which extends the capabilities of NUnit, creating the appropriate framework to test Web user interfaces.

 

NUnitAsp tests are written using AspControlTester objects that mimic the ASP.NET Web controls. For instance, to test a TextBox you would use a TextBoxTester. For a Button, a ButtonTester. By instantiating a tester control for each ASP.NET control, a developer can populate a TextBox, select an item from a DropDownList, or click a Button using .NET code inside a controlled testing environment. The concept is easiest to understand in the context of an example, so let s begin with a sample application.

 

Installation

To begin, download the latest version of NUnitAsp, available at http://nunitasp.sourceforge.net/download.html. Installation is a breeze, and is detailed at http://nunitasp.sourceforge.net/installation.html.

 

The Sample Application

To demonstrate the capabilities of NUnitAsp I ve created a one-page sample application that simulates a basic user registration form (all code used in this article is available from the asp.netPRO Web site; see end of article for download details). The form prompts for an e-mail address, password, and name, and displays a confirmation message if registration is successful, hiding the original form via a panel. The page includes regular expression validation on the e-mail address, and required field validation on the e-mail address and password. It also contains a ValidationSummary to aggregate the validator error messages. A screen shot of the design view is shown in Figure 1.

 


Figure 1: Design view of the Registration page.

 

The code-behind contains the event handler for the Register button and a Private method called RegisterUser. In this example, RegisterUser is a stub; however, in a production implementation it would likely contain some database access code. Assuming the user is registered successfully, the panel containing the form is hidden and the panel containing the confirmation message is displayed (see Figure 2).

 

Private Sub btnRegister_Click(ByVal sender As System.Object,

                             ByVal e As System.EventArgs)

                             Handles btnRegister.Click

 ' Perform server-side error checking

 If Not Page.IsValid Then Exit Sub

 Try

   ' Register the user

   RegisterUser()

   ' Display Confirmation to user

   pnlForm.Visible = False

   pnlConfirmation.Visible = True

 Catch ex As Exception

   lblError.Visible = True

   lblError.Text = ex.ToString

 End Try

End Sub

Private Sub RegisterUser()

 ' User registration code would be here...

End Sub

Figure 2: Code-behind for the Registration page.

 

Preparing to Write a Test

Individual test methods, also known as tests, are contained in .NET classes, also known as Test Fixtures. To test the Registration application, I created a class library in Visual Studio.NET called RegistrationTest. To access the required NUnit and NUnitAsp classes, this project requires references to the two dlls shown in Figure 3. The class file RegistrationTest.vb contains the Test Fixture (see Figure 4).

 

DLL Name

Default Location

nunit.framework.dll

C:\Program Files\NUnit 2.2\bin\

NUnitAsp.dll

C:\Program Files\NUnitAsp\bin\

Figure 3: DLL references needed to use NUnitASP.

 

Imports System

Imports NUnit.Framework

Imports NUnit.Extensions.Asp

Imports NUnit.Extensions.Asp.AspTester

Public Class RegistrationTest

 Inherits WebFormTestCase

 ' Panels

 Private pnlForm As PanelTester

 Private pnlConfirmation As PanelTester

 ' Form elements

 Private valSummary As ValidationSummaryTester

 Private txtEmail As TextBoxTester

 Private txtPassword As TextBoxTester

 Private txtName As TextBoxTester

 Private btnRegister As ButtonTester

 Protected Overrides Sub SetUp()

   ' Panels

   pnlForm = New PanelTester("pnlForm", CurrentWebForm)

   pnlConfirmation = New PanelTester("pnlConfirmation",

                                     CurrentWebForm)

   ' Form elements

   valSummary = New ValidationSummaryTester("valSummary",

                                            CurrentWebForm)

   txtEmail = New TextBoxTester("txtEmail", CurrentWebForm)

   txtPassword = New TextBoxTester("txtPassword",

                                   CurrentWebForm)

   txtName = New TextBoxTester("txtName", CurrentWebForm)

   btnRegister = New ButtonTester("btnRegister",

                                  CurrentWebForm)

 End Sub

  . . .

Figure 4: The basis of our Test Fixture.

 

Notice that this class imports three NUnit namespaces. These imports statements are only valid if the references mentioned above have been added. These three namespaces contain the core features used in our Test Fixture.

 

Next, notice the attribute, which designates that this class contains tests. You can run tests without a attribute, but it is considered poor style. Test Fixtures must be public classes, and must have a default constructor.

 

Also notice that RegistrationTest inherits from WebFormTestCase. WebFormTestCase is an NUnitAsp class that establishes the context of this Test Fixture and allows it to use objects such as Request, Response, and Server, even though the class is not running in the ASPNET worker process.

 

Next comes the tester object declarations. Notice I ve declared one tester for each form element, and I ve made the names identical to their ASP.NET counterparts. A complete list of tester objects is available at http://nunitasp.sourceforge.net/api/NUnit.Extensions.Asp.AspTester.html.

 

Figure 4 concludes with the SetUp method, which instantiates a new instance of each tester object. To instantiate a tester object you must provide a string containing the name of the object to be tested, along with its container. CurrentWebForm, a property of WebFormTestCase, is the container that you will most often use.

 

SetUp runs before each individual test, so it should be used to perform common initialization tasks. Its partner method, TearDown, is not used in this example, but is run after the completion of each test. If you re familiar with NUnit, you re probably wondering why I chose to override these methods instead of using the or attributes. NUnitAsp, being built on top of NUnit, uses these attributes to maintain the proper context for ASP.NET code to execute. If you use or in your test code, your tests will not function properly. Suffice to say, overriding SetUp and TearDown is the proper way to proceed.

 

The First Test

The first test for any Web page should be TestLayout, which confirms that the appropriate form elements are visible (see Figure 5). Notice the attribute; this test will run without it, but as with , it is considered poor style. Methods marked with should not accept parameters or return a value.

 

' Tests the basic layout of the form

Public Sub TestLayout()

 Browser.GetPage("http://localhost/Registration/

                 Register.aspx")

 AssertVisibility(valSummary, False)

 AssertVisibility(txtEmail, True)

 AssertVisibility(txtPassword, True)

 AssertVisibility(txtName, True)

 AssertVisibility(btnRegister, True)

 AssertVisibility(pnlForm, True)

 AssertVisibility(pnlConfirmation, False)

End Sub

Figure 5: TestLayout confirms that the appropriate form elements are visible.

 

The first step in testing the layout is to use the built-in Browser object to retrieve the page from the Web server. After that, we can assert the visibility of each item, ensuring that the Validation Summary and confirmation Panel are invisible when the page loads, and that all of the remaining elements are visible.

 

Now that the first test is written, let s take a look at how to run it.

 

Running a Test

NUnit comes with both a console and a Windows Forms interface. Being a UI developer, I prefer to use Windows Forms, and there are two ways to invoke it.

 

The first is by navigating to the nunit-gui.exe through your Start menu (Start | Programs | NUnit 2.2 | NUnit-Gui). Once the application starts, click File | Open and search for your test DLL (in this case, RegistrationTest.dll).

 

The second way is to set nunit-gui.exe as a Start Action for your test project in Visual Studio.NET. I prefer this method, because it allows easy step-through of both your test and application code during test execution. To set this up, right-click the RegistrationTest project in Visual Studio.NET and select Properties. Under Configuration Properties in the left panel choose the Debugging menu item. Under Start Action, select the Start External Program radio button and browse to the nunit-gui.exe location, which is C:\Program Files\NUnit 2.2\bin\ by default. Click OK to close the window. Finally, right click on RegistrationTest again and set it as the start up project. Now when you hit F5 in Visual Studio.NET, the NUnit GUI will start.

 

In either scenario, once NUnit has opened you ll see a hierarchy of your tests in the left panel and empty test results in the right panel. Clicking the Run button will execute the tests and, using color-coding, display whether they have passed (green), failed (red), or been skipped (yellow); see Figures 6 and 7.

 


Figure 6: The NUnit GUI display; all tests passed.

 


Figure 7: The NUnit GUI display; one test failed.

 

Other Tests

After you ve tested your form layout there are many different tests you could write, even for this fairly simple page. The key is to write tests that exercise the significant variations of input to your page.

 

I ve created the following tests for Register.aspx (these tests are included in the downloadable code; again, see end of article for details):

  • Submitting an empty e-mail
  • Submitting an empty password
  • Submitting an incorrectly-formatted e-mail
  • Submitting a valid registration

 

Because they all function in essentially the same way, I ll examine two of these tests and leave the rest for the reader to explore.

 

The TestEmptyEmail test begins by getting the Registration page from the Browser object, then setting the Text properties of the three textboxes; note that Email, a required field, is empty (see Figure 8). Calling the Click method of the ButtonTester simulates a user clicking this button in the browser. Our expected behavior is an error message telling the user that Email is a required field. We test this by examining the Messages array of the ValidationSummaryTester object. Because arrays are zero-based, the 0th message is the first one displayed. In this case, we use AssertEquals, which has several overloaded forms. The one used here accepts a message to display if the test fails, and two strings that should be equal. If they are not equal, the test fails.

 

' Tests the behavior of the form when email is empty

Public Sub TestEmailEmpty()

 Browser.GetPage("http://localhost/Registration/

                 Register.aspx")

 txtEmail.Text = String.Empty

 txtPassword.Text = "password"

 txtName.Text = "Rob Walling"

 btnRegister.Click()

 AssertVisibility(valSummary, True)

 AssertEquals("Error message did not appear.",

              valSummary.Messages(0).ToString,

              "Email is a required field.")

End Sub

Figure 8: The TestEmptyEmail test.

One important note: NUnitAsp uses HTTP GET and POST methods, so client-side form validation does not execute when the Register button is clicked. As a result, you must be sure to use server-side form validation to properly test your validators.

 

The TestSuccessfulRegistration test once again retrieves Register.aspx using the Browser object (see Figure 9). In this case, the form is filled out correctly, the button is clicked, and the visibility of the confirmation panel is confirmed. In addition, we confirm that the Validation Summary and form Panel are now hidden.

 

' Tests a successful registration

Public Sub TestSuccessfulRegistration()

 Browser.GetPage("http://localhost/Registration/

                 Register.aspx")

 txtEmail.Text = "[email protected]"

 txtPassword.Text = "password"

 txtName.Text = "Rob Walling"

 btnRegister.Click()

 AssertVisibility(valSummary, False)

 AssertVisibility(pnlForm, False)

 AssertVisibility(pnlConfirmation, True)

End Sub

Figure 9: The TestSuccessfulRegistration test.

 

Conclusion

I urge you to explore the numerous articles and tutorials published on NUnitAsp to gain more exposure to this powerful tool; begin with the resources available on the NUnitAsp Web site. Remember that writing a test takes time, but once complete, it works for you each and every time you run it.

 

Additional Resources

Visit these sites for more information on getting started with NUnitASP:

 

The sample code referenced in this article is available for download.

 

Rob Walling is a Microsoft Certified Application Developer (MCAD.NET) with five years of development experience. His areas of expertise include ASP.NET, VB.NET, and Web application architecture. His technical articles appear in various .NET-related Web sites and publications. You can reach him at mailto:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish