Unit Tests

The goal for the unit tests is to verify that all the required functionality is actually implemented and that the various modules are working in isolation. For the photo editor application, most of the required functionality is implemented in the Picture class. The only exception is the GUI. It is cumbersome to test the GUI automatically, and it is more an integration test rather then a unit test task. Therefore, the F:photo_editor key is not explicitly tested at the unit test level.

To test the load and save functionality, it would be an advantage to have overloaded methods where the test could specify the file name to be loaded or saved. With the current implementation of the Picture class, the file dialog would open every time the load functionality is called, making the automated tests very difficult. You can use a commercial capture replay tool to exercise these kinds of actions. Tools such as WinRunner do a good job on those things. But as mentioned, the easier solution (and probably the nicer solution as well) is to add two overloaded methods to the Picture class. The one overloaded method is the load method, which accepts a parameter of type string; the other is the save method, which also accepts a string parameter. The overloaded methods then load or save the picture under the provided file name. The implementation can be seen in Listing 5.16.

Listing 5.16 The Overloaded Save and Load Methods of the Picture class

///

/// Opens the file with the provided name. ///

///name of the file to be opened /// F:image_load_and_save public void LoadImage(string fileName) { Bitmap oldImage; oldImage = loadedImage; loadedImage = new Bitmap(fileName); if(loadedImage == null) { throw(new Exception("Error, LoadImage with file name failed")); } oldImage.Dispose(); } ///

/// Saves the current image /// with the provided fileName. ///

///Name under which the image is saved public void SaveImage(string fileName) { loadedImage.Save(fileName); }

These two hooks can now be used by the test program to actually load and save an image without having to go through a file load and save dialog box. Very often, such hooks are implemented for testing. This is another reason to include the test team (if there is a separate test team available) in the project planning from the beginning. In this way, hooks for testing can be discussed in the planning phase of the project and implemented as features during development. In the photo editor project, this not as important because the development team also does the testing. Nevertheless, testing is incorporated in the project planning from the beginning.

5.7.1 The NUnit Test Framework

To test the Picture class functionality, an automated test framework would be very helpful. The framework we are looking for should be capable of running specified tests automatically, and it should show the result on the screen. Ideally it would have a GUI we could use to run selected tests, or it would run the tests from the command line (to let us run the tests every night using a script). It also should be easy to use so that we don't have to spend much time in training and setting up the test framework.

Luckily, such a test framework exists. Called NUnit, this framework is an automated test framework that is implemented for many programming languages in a similar form (for example, JUnit for Java, CppUnit for C++, and many more). The unit test framework was first developed for Smalltalk by the extreme programming group around Kent Beck. Later, the framework was ported to many languages and is now also available for Microsoft .NET as NUnit. The framework can be downloaded from http://www.nunit.org. A quick-start guide and other documentation can be found at the site.

5.7.2 Unit Test Implementation

After downloading and installing the NUnit framework, we develop the tests (you will also find an installation of the NUnit test framework in the src directory). First, add a new class to the photo editor application project with the name UnitTest.

Add a reference to NUnit.framework.dll (which can be found in the srcNUnit20in directory), and add a using statement for NUnit. Framework. To use the classes provided by the Picture class, also add a using statement for the System.Drawing namespace that defines RotateFlipType. To tell the framework that the class UnitTest contains unit test methods that are executable by NUnit, we add an attribute called [TestFixture] before the class definition. Before implementing the actual test methods, we implement the setup and tear-down methods of the tests by inheriting two attributes from the unit test framework. The SetUp method is called before a test method is called, and the TearDown method is called after the test method is executed. The attributes used to indicate these methods are [SetUp] and [TearDown].

For the unit tests of the Picture class, the SetUp method creates a new Picture object and writes to the standard output that a new test has started. In the TearDown method, the image is disposed of and an indication of the test result (passed or failed) is written to the standard output. Listing 5.17 shows the SetUp and TearDown implementation.

Listing 5.17 The Unit Test SetUp and TearDown Methods

namespace UnitTest { [SetUp] public void Init() { Console.WriteLine("********* New Test-case: *******"); Console.WriteLine("photo_editor"); TestImage = new Photo_Editor_Application.Picture(); } private Photo_Editor_Application.Picture TestImage; private bool amIPassed = false; [TearDown] public void Destroy() { TestImage.LoadedImage.Dispose(); if(amIPassed) { Console.WriteLine("=> PASSED"); } else { Console.WriteLine("%%%%%% Failed"); } } }

For the file load test, we load the default image and check whether the loaded image has the correct dimensions. The save file test crops the image and saves it under a new file name. Then the regular default image is loaded again (to make sure the Picture object has been changed and has the original dimensions again) before the saved image is loaded. The saved image is checked to see whether its dimensions are the same as the cropping image information that was provided before the image was saved. The XML tag identifies which requirement key is tested in this test. To indicate that a method is a test method, the attribute [Test] is used before the method definition. The implementation can be seen in Listing 5.18.

Listing 5.18 Image Load and Save Test

///

/// Test for F:image_load_and_save. /// Windows standard dialogs are used, so really /// this tests only whether the default image loaded has the /// dimensions /// that are expected! ///

/// F:image_load_and_save [Test] public void LoadandSaveImageTest() { const string fileName = "Test.jpg"; Console.WriteLine("image_load_and_save"); Assertion.AssertEquals("Load Image, width", TestImage.LoadedImage.Width, 2048); Assertion.AssertEquals("Load Image, height", TestImage.LoadedImage.Height, 1536); TestImage.CropImage(200, 400); TestImage.SaveImage(fileName); TestImage.LoadImage("Hawaii.jpg"); TestImage.LoadImage(fileName); Assertion.AssertEquals("Load Image, width", TestImage.LoadedImage.Width, 200); Assertion.AssertEquals("Load Image, height", TestImage.LoadedImage.Height, 400); amIPassed = true; }

We perform the actual test case by calling an Assertion method with the pass/fail criteria. If the test case fails, then the test is failed and the rest of the tests within this method are not executed even if there are more test cases defined. That is why the flag amIPassed can be set to true in case the end of the method is actually reached.

Do It Yourself

Implement test cases for image cropping, rotating, and flipping in the same way it was done for loading and saving. Check the unit test project into Source Safe. A sample solution is provided with the source code on the accompanying CD.

Now that the test cases have been implemented it is time to run them to see whether the developed program actually does what it is expected to do. We can run the test either from the command line or via the NUnit GUI. In this chapter only the GUI is shown.

To start the tests, go to the Start menu; then go to Programs | NUnitV2.0 | NUnit-GUI. The NUnit GUI will open. Choose File | Open and navigate to the directory where the unit tests were built. The test tree will be shown, and the tests can be run by pressing the Run button. The result will look like Figure 5.19.

Figure 5.19. The NUnit GUI

The GUI gives a nice overview of the test result. If the progress bar is green, it means that all test cases passed. Otherwise, the bar will be red.

The Standard Out tab shows the results that were logged during the test run. If there are errors, information about the failed cases can be found in the Errors and Failures tab.

Категории