Through the unit test inheriting from the custom user
control, there are some additional capabilities you get from doing so, such as
implement the observer
pattern. The user control class can setup or change the property values of
various inner controls. For instance, other controls can be exposed through
public properties of the user control base class, and the various properties
can be set, as shown below.
Listing 3
public abstract class AssignmentUserControlBase
{
protected abstract DetailsView AssignmentDetailsView
{
get;
}
protected abstract GridView AssignmentsView
{
get;
}
protected abstract TextBox SearchTextBox
{
get;
}
protected override void OnInit(EventArgs e)
{
this.AssignmentsView.DataKeyNames = new string[]
{
"AssignmentID"
};
this.AssignmentsDetailsView.Visible = (this.AssignmentsView.SelectedIndex >
- 1);
this.SearchTextBox.Enabled = (this.AssignmentsView.SelectedIndex == - 1);
}
}
As another example, I had an application that allowed access
to a registration page only at certain times. The application only allowed
registrations before Wednesday afternoon. After that time, registration was
shut down and the registration began again on the next day on Thursday,
registering users for the following week.
The approach I used was to create a method that returned the
current date, and was defined as protected virtually. In all situations in the
real application, this method returned DateTime.Now; however, using this
approach allowed me to mock the return value by overriding the method in the
unit test and returning the value of a local variable. The overridden method in
the unit test looks like this:
Listing 3
private DateTime _currentDate = DateTime.Now;
protected overrides DateTime GetCurrentDate()
{
return _currentDate;
}
The method returns the current date to the OnInit method in
the custom user control class, which controls the times when the application is
accessible. The following is that method definition.
Listing 4
protected overrides void OnInit(EventArgs e)
{
DateTime currentDate = this.GetCurrentDate();
if (currentDate.DayOfWeek == Wednesday)
{
if (currentDate.Hour >= 15)
//Avoid registration page
else
//Allow registration, display warning
}
//Else allow access to application
}
The following unit test can test this logic thoroughly
because it overrides the GetCurrentDate method and returns the local date
variable with a predefined value, which tests the various flows through the
OnInit method. The following test asserts that all of the appropriate conditions
do what they are meant to do. In instances when the current time is passed the
fifteenth hour (past 3 PM), the page should redirect. If it is before that, a
warning should be displayed; otherwise, general page access is allowed. The
following test can test all of that.
Listing 5
[Test]
public void TestInitialLoad()
{
_currentDate = new DateTime(2007, 7, 11, 9, 0, 0);
this.OnInit(EventArgs.Empty);
//assert that the registration is allowed, and a warning is displayed
_currentDate = new DateTime(2007, 7, 11, 16, 0, 0);
this.OnInit(EventArgs.Empty);
//assert that the registration is blocked
_currentDate = new DateTime(2007, 7, 12, 7, 0, 0);
this.OnInit(EventArgs.Empty);
//assert that the registration is allowed for the next week
}
If a user control dynamically generates the controls within
it, it is possible to test that as well. For instance, assume that a
server-side table is dynamically generated on page load, adding certain
controls within certain cells to control the layout. The text within those
controls may be dynamically generated from data in this situation. Everything
in regards to that process can be tested to ensure the table renders correctly.
Take the test below. The first part defines the abstract property that must be
overridden (which allows the custom user control class to make use of the
visual elements in the ASCX user control). Then, the table's structure is
validated after it is initialized (initialization is called in the test's setup
method).
Listing 6
private Table _layoutTable = new Table();
protected override Table LayoutTable
{
get
{
return _layoutTable;
}
}
[Test]
public void TestTableGeneration()
{
Assert.AreEqual(3, _layoutTable.Rows.Count);
Assert.IsInstanceOfType(typeof(Label),
_layoutTable.Rows[0].Cells[0].Controls[0]);
Assert.AreEqual("Search Text:", ((Label)
_layoutTable.Rows[0].Cells[0].Controls[0]).Text);
Assert.AreEqual(2, _layoutTable.Rows[1].Cells[0].ColumnSpan);
Assert.IsInstanceOfType(typeof(GridView),
_layoutTable.Rows[1].Cells[0].Controls[0]);
Assert.AreEqual("5 rows found", _layoutTable.Rows[2].Cells[0].Text);
}
This makes it possible to use Test-Driven Development (TDD)
to formulate the structure of the user control and to test the layout creation
of the user control.