RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


.NET Building Blocks: Custom User Control Fundamentals : Page 3

Find out the gritty details required to create, test, use, inherit, install, and distribute .NET User Controls of all types.

Another Look at the Test Container
If you are an aficionado of test-driven design, you know that unit testing of UI components always presents its own set of difficulties. The UserControl Test Container of Visual Studio exemplifies a good intermediate step between automated unit testing and manual UI testing at the application level. The test container is still manual UI testing, but it allows you to test a single unit (control) rather than having to test an application in its entirety. I call isolated unit testing container testing.

The AlarmClockControl that you built provides sufficient means to exercise the control, via the AlarmTime property, the AlarmSet property, and the Disable Alarm button. However, AlarmClockControl is probably in the minority; generally user controls will not provide sufficient means for meaningful testing in isolation. Therefore, you must usually instrument your control for container testing, just as you have to instrument non-UI code for unit testing. For this discussion, take a look at the ProgressBarMessager control running in the test container (see Figure 9). This control comes from my .NET open source software collection (get the API, or download the control collection). The purpose of this control is to enhance a standard ProgressBar to support progress messages that appear sequentially beneath the bar and can provide useful feedback during a lengthy operation. The ProgressBarMessager control also includes a button so users can cancel the operation if desired.

Figure 9. The ProgressBarMessager Control: Unlike the AlarmClockControl, this control does not run autonomously; instead, it's instrumented with an extra ContainerTest property for the express purpose of container testing. Enabling that property causes an action that allows the control to be exercised in the test container.

The ProgressBarMessager has an added property called ContainerTest that defaults to false (see Figure 9). The intent is that changing the ContainerTest property to true should reveal additional controls that are necessary and sufficient to enable testing this control in isolation, without having to first embed it in a master form and hook it up manually. In this case, when you set ContainerTest to true, the control responds by displaying a hidden Step button. This button performs one step in the natural action of a progress bar. For example, the sequence of frames in Figure 10 begins at the upper left with the Step button exposed; subsequent frames in the image result from pressing the Step button repeatedly.

Figure 10. Testing the ProgressBarMessager: Repeated Step button presses let you test the progress bar, causing additional messages to appear. The control expands vertically up to a preset size, and then scrolls.
The first press displays an initial message with a small green arrow, indicating it is the current step being executed. That corresponds to a call to Reset() followed by a call to ReportInitialMessage(). Subsequent Step presses correspond to calls to the PerformStep() method. The second press, therefore, changes the arrow in front of the first message to a check and adds an elapsed time for that step. It then adds the second message ("step 2") and an arrow indicating that is now the step being executed. Continued presses of the button add more steps. Note that the control expands vertically to contain a property-selectable number of messages (10 by default). Continued presses beyond that simply scroll the messages, as the final frame in Figure 10 shows.

When to Test
Testing a control embedded in a complete application or in the UserControl Test Container are both aspects of run-time testing. But one of the cleverer features of Visual Studio is something you might never notice: the ability to execute your code at design-time. You may have already noticed this in action when building the examples in this article. For example, the AlarmClockControl showed its parent control (ClockControl) in the designer with a time display that updated every second—without executing anything! That clock, as you know, gets updated by your timer tick event handler, so it is clearly running your code.

You aren't limited to passive observation as your code executes; you can interact with the design-time execution of your program by manipulating properties. For example, if you change the AlarmClockControl's ClockForeColor property in the Properties window of the designer, you are in fact accessing the code that manages that property:

   public Color ClockForeColor
      get { return clockLabel.ForeColor; }
      set { clockLabel.ForeColor = value; }
Specifically, changing the property invokes the ClockForeColor setter, which, in this case, executes just one line of code: the assignment to the ForeColor property of the underlying label. But you are not limited to simple assignments, as evidenced in the aforementioned timer tick event handler.

So what about .NET controls? Placing a Label on your designer surface, and then changing the BackColor property of that label does the same thing; it executes the setter property of the Label control. In other words, Visual Studio produces the design-time display of a control by executing the code that renders of that control. For further exploration of this topic, see the MSDN topic "Extending Design-Time Support."

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date