Monday, September 24, 2007

Hidden Desktops and NUnitForms

In my last post I noted a problem working with NUnitForms. I was unable to get the hidden desktop to work with a [SetUp] method. After digging through the source code, I have my solution.

The code that sets up the hidden desktop is in the method init(). This method is marked with the [SetUp] attribute. When I created my own method with this attribute, init() was no longer being called. Thus, no hidden desktop.

The solution is to override the Setup() method provided in NUnitFormsTest, but to not mark it with the [SetUp] attribute. The last thing init() does before exiting is make a call to Setup(). The TearDown attribute and method have a similar implementation.

When the documentation seems to be lacking, it's always nice to have the source code.

Friday, September 21, 2007

WinForms testing using NUnitForms

I've been spending a lot of time lately coding screens for a WinForms application. Although I've written unit tests for the server components, the client side is somewhat lacking. Each time I change a screen I have to manually test those changes and verify I didn't break anything. In an attempt at automating the process, I've started looking at NUnitForms, an extension to NUnit.


1) Install NUnitForms
2) Create a project for your NUnit tests. Configure NUnit as normal.
3) Add references to your application project, NUnitForms, System.Windows.Forms, and any third-party controls you use on your application's forms.
4) In the test fixtures, add 'using NUnit.Extensions.Forms'

Basic forms testing

Let's say my application under test (AUT) contains a form, Form1. The first step is to create and display an instance of that form

Form1 testForm = new Form1();

Say the form has a button - btnOne. Pressing the button programatically looks like this

ButtonTester btnOneTester = new ButtonTester("btnOne");

Upon clicking this button, a label was updated with the everyone's favorite power tool. To verify

LabelTester labelOneTester = new LabelTester("labelOne");
Assert.AreEqual("Chainsaw", labelOneTester.Text, "Label text doesn't match expected");

Though it's not required, it's probably a good idea to close the form instead of letting it fall out of scope


Using the hidden desktop

Running these tests on your local machine doesn't pose any issues. If you run them on a build server, however, you'll likely find that they fail - there's no window for the forms to be displayed in. Fortunately, you can send them to a hidden desktop.

To do so, your test fixture must inherit from NUnitFormTest. Then, add the following property to the class

public override bool UseHidden
get { return true; }

One warning - In most of my test fixtures, I tend to put common code in a [Setup] method. I'm finding that when I have this defined, forms are not being sent to the hidden desktop. I've not spent much time on it, so I'm not sure if it's something I'm doing wrong, or if it's a bug in the tool. I'll post more info if/when I figure it out.

Sunday, September 16, 2007

Silverlight preparation

A friend recently decided to start a monthly Hack Day for a small group of colleagues. Given that it's often difficult to motivate oneself to study new technology, the idea is to gather like-minded slackers and force each other to do a little research.

After some discussion, we decided on Silverlight as the first topic. Here's what I did in preparation:

1) Downloaded a VPC image of Orcas (aka VS2008.) You have to download a base image along with the Orcas image - nearly 14GB total.

2) Installed various 1.0 and 1.1 packages:

Silverlight 1.0 Runtime
Silverlight 1.0 SDK
Silverlight 1.1 Alpha Refresh
Silverlight Tools for VS2008
Expression Blend 2 August Preview

3) Watched the Getting Started video and a few Blend tutorials

Uncompressed images and file sizes

Scanning paper documents can be a useful way to transfer and store data. This of course assumes you are scanning bitonal, with some form of image compression. If you were to scan in 24-bit color with no compression, you'd find the output less than useful.

To see this, let's start with a 1 inch square, at 10 dots per inch (dpi.) The total number of dots (pixels) is 10x10, or 100. If we create a larger square, say 5 inches on each side, we now have 25 square inches. At 10dpi, that's 2500 pixels (100 dots per square x 25 squares.) If we scanned a normal sheet of paper (8.5x11) we have a total of 93500 pixels.

Going back to the 1 inch square, say we double the dpi to 20. What does that do to the pixel count? You might initially say it doubles. If you calculate it, however, you find that you quadrupled the number (20x20 = 400.)

The total number of pixels can be found using the formula:

(horizontal dpi * image width in inches) * (vertical dpi * image height in inches) = total pixels

A normal sheet of paper, scanned at 100dpi

(100 * 8.5) * (100 * 11) = 935,000 pixels

The other item to consider is the bit depth of the image. For a bitonal image, each pixel is represented by 1 bit (black or white.) Color images, such as photos, are saved with RGB values for each pixel. This typically requires one byte per color, or three bytes per pixel

To calculate the total number of bytes per image:

total pixels * bytes per pixel = total bytes

A normal sheet of paper, again at 100dpi, scanned in 1 bit-per-pixel (bpp)

935000 * 0.125 = 116,875 bytes

That same page, scanned in 24bpp

935000 * 3 = 2,805,000 bytes (~2.5MB)

As you can see, scanning in full color without compression creates much larger images. Again with 24bit color, here are some common scanner dpi's with their resulting image sizes (in bytes.)

200 dpi = (200 * 8.5) * (200 * 11) * 3 = 11,220,000

300 dpi = (300 * 8.5) * (300 * 11) * 3 = 25,245,000

600 dpi = (600 * 8.5) * (600 * 11) * 3 = 100,980,000

Tuesday, September 4, 2007

Upgrading from NUnit 2.2 to 2.4

Until recently, I was running NUnit 2.2.9 on both my work and home computers. This weekend I decided to upgrade my home computer to version 2.4.3. The quick and painless process went as follows:

1) Uninstall v2.2.9
2) Install v2.4.3
3) Open an existing project containing unit tests
4) Updating the references to point to the new assemblies
5) Compile and run...

Well, it all worked except for that last step. At one point, I seem to recall NUnit requiring you to reference nunit.core. Whatever that reason, it's no longer a requirement, and was the cause of the build failure. After removing the reference, everything ran as before.

Constraint-based assertions

One of the most noticeable changes in version 2.4 was the inclusion of constraint-based assertions, similar to some of the mock frameworks available. Previously, you might write assertions like:

Assert.IsTrue(age < 21);
Assert.AreEqual(9, age);

Using constraints, you can now write:

Assert.That(age, Is.LessThan(21));
Assert.That(age, Is.EqualTo(9));

Also, if your test fixture is derived from AssertionHelper, you can shorten the previous lines to:

Expect(age, LessThan(21));
Expect(age, EqualTo(9));

Note: you will need to add using statements for NUnit.Framework.Constraints and NUnit.Framework.SyntaxHelpers. For more examples, including comparisons to the older Assert methods, look for AssertSyntaxTests.cs under the NUnit install directory.