Working with NUnit tests

From OpenPetra Wiki
Revision as of 11:28, 12 February 2013 by Alanjfpaterson (talk | contribs)
Jump to navigation Jump to search

Instructions

  • Download the latest version from https://launchpad.net/nunitv2/ Choose the latest version and NOT the one for .NET v1.1. At the time of writing this the download choice is NUnit-2.6.0.12051.msi.
  • Install this file on your PC using the default options
  • Build the entire Open Petra solution
    • either by running nant generateSolution once; then running nant compile will compile the tests for OpenPetra (and re-running it will recompile the tests)
    • or by doing the same thing using the Developer's Assistant
  • You will find the resulting tests in dlls in the directory delivery/bin/ along with all the dlls that make up the Open Petra run-time.

Now you are ready to start testing...

  • Open NUnit (which you installed as part of the msi above) from the start menu
  • Choose File | Open Project to open the dll that you want to test, eg. Tests.Common.dll.
  • You can now run a single test, or run all tests at once, depending on which item in the tree you select
    • Note: run the 32 bit version of NUnit if you are on Win 7 (found in %ProgramFiles(x86)% and usually has "x86" in the executable name).

If all your test(s) pass, you will see a nice green bar across the top of NUnit. If any test fails the bar will be red. You will (usually) get helpful pointers to the part of the test that failed.

Important Note: If you are running a simple test or a server test you probably don't need to have the server console running at all. If you are running a client test, you will definitely have to start the server console before you run the test. If you forget to do this, the 'error' message that you get when the test fails (as it will) is not very helpful and unlikely to remind you to start the server - until you have seen this unhelpful message for the twentieth time!

Available Tests

  • We have quite simple function tests, eg. in csharp\ICT\Testing\Common (which tests a lot of the functionality of Ict.Common)
  • We have tests for string operations (TStringHelper), Database operations, CSV&XML Input/Output, etc.
  • We have tests to prove the correct operation of the server and database
  • We have tests to prove the correct operation of several of the client screens
  • We have a test to validate 'printed' output
    • The test in csharp\ICT\Testing\Common\Printing does not use the NUnit framework, but allows the user to see how an HTML file gets printed to paper or PDF.

File System Organisation for Tests

Test DLLs are organised in our folder structure beneath csharp\ICT\Testing. Most tests tests are in a lib sub-folder which is then further categorised by module feature (MCommon, MFinance, MPartner etc). You should further separate out specific server tests from client tests.

Anatomy of a Test Class

Start by reading the NUnit help, as well as looking at some existing examples of Open Petra tests. You will soon discover that test methods carry attributes such as [SetUp], [Test] etc. In fact all your public methods will need an attribute. This is for setting up the testing environment, cleaning it up afterwards, defining which method is a test and so on. You will also probably have a few private helper methods for doing repetitive tasks in your code.

Each [Test] method needs to set up its data, perform the action to be tested and then probe the result(s) using one or several of the 'Assert' overloads such as Assert.IsTrue() or Assert.AreEqual(). A good test method will have a few lines of code to set up the test - by making a call into the class being tested - and then a number of assert lines that test for successful execution. It is also a good practice to separate out the data initialisation part into a private helper method so that it is easy to read what the test is doing from the code.

Writing New Tests

When you are writing a new test you need to think about the following.

  • Can this test be added as a new test class (as a new .cs file) to an existing test DLL?
  • If you decide that there are a large number of tests to write on a new subject, then you will probably decide to start a new project DLL. In that case, where will the new project live in our Testing hierarchy?
  • What data will the new test need to work with (if any)? All our tests so far use the 'demo' database, which starts with a limited amount of content. That is normally a good thing for testing as it allows you to set up the starting condition that you want. However you will need to think whether your test needs to be sure to start with a particular table in an empty state or whether you can start with any prior data condition and whether your test can delete any data that you add.
  • Having decided what the working data is going to look like, it is quite a good idea to create a testData.cs file (perhaps as a partial class of the main test class) and define the data handling methods that you will make use of in that file. This helps to keep your test file cleaner. See for example csharp\ICT\Testing\lib\MFinance\ExchangeRates\CorporateDataSet.cs which is a partial class of csharp\ICT\Testing\lib\MFinance\ExchangeRates\CorporateRate.test.cs.
  • Plan carefully exactly what tests need to be carried out in order to prove the functionality of the target code being tested. Think about how to make sure that the maximum amount of the target code can be forced to run. This will mean arranging to run a nice test that succeeds, but also to set up conditions where the target code is made to run with 'bad' input conditions and prove that it handles those correctly.

You may well be able to copy an existing .cs file and use it as the basis of your new test class. If you need to start a new project (DLL) then

  • decide where it will be located in the existing file structure and create a new folder for it.
  • add a typical test code file to the folder (copy an existing one and then delete all the content except maybe the Setup and TearDown parts).
  • set the namespace to match the location you have chosen.
  • include at least the #using statements indicated below

Now using Nant or the Developer's Assistant, generate the full solution (if you are already up to date this can be with a minimal compile). Load the Open Petra Testing solution. You will have a new project created for you with some initial project references.

As you write your tests you will likely need to add further project references. You can work out what these references are from the target code. You then can use the IDE to add a reference to your test project, but make sure to add a #using statement as well. Then you can be sure that when you re-generate the whole solution and the projects are re-created the references will all be correct.

Here are the minimum required references for a server project:

using System;
using System.Data;
using NUnit.Framework;
using Ict.Testing.NUnitPetraServer;
using Ict.Common.Data;
using Ict.Common.DB;
using Ict.Common.Remoting.Server;
using Ict.Common.Remoting.Shared;
using Ict.Petra.Server.App.Core;

Here are the likely candidates for a client test

using System;
using System.Windows.Forms;

using NUnit.Extensions.Forms;
using NUnit.Framework;

using Ict.Testing.NUnitForms;
using Ict.Testing.NUnitPetraClient;
using Ict.Testing.NUnitTools;

using Ict.Common;
using Ict.Common.IO;
using Ict.Common.Controls;
using Ict.Petra.Client.CommonControls;
using Ict.Petra.Client.CommonForms;


The [Test] methods have to be able to run in any order. If they alter the database they have to set the database correctly for the test and then (possibly) delete any changes they have made.

Server Tests

In some respects, server tests are easier to write than client tests. We have already seen that usually it is not even necessary to run the server console separately in order to execute a server test. The test itself is probably simpler to write and the number of separate 'Asserts' required to prove success is probably fewer


Client forms test

NUnitForms

We make use of NUnitForms (http://nunitforms.sourceforge.net/). The project is alive, even though the last release is a couple of years old. We have our compiled dll of the latest VCS snapshot in our own VCS, in csharp\ThirdParty\NUnit.

We have made small modifications to NUnitForms so that it works for our generated forms with all the random Layout control names blurring the path to controls. The modifications are maintained in csharp\ThirdParty\NUnit\src.

Integration tests

Basically, these tests are integration tests, since our DLL Ict.Testing.NUnitClient.dll (project in csharp\ICT\Testing\NUnitPetraClient) is a full OpenPetra client, allows a demo user to login to the separately running server, and then open OpenPetra screens as if it was a normal user. There is currently no mock-up server.

Existing tests with samples

  • We have a project in csharp\ICT\Testing\MFinance\GLForm which does create GL Batches, post them, and does some checks.

Server function tests

We have a full server wrapped up in a dll, in csharp\ICT\Testing\NUnitPetraServer, Ict.Testing.NUnitServer.dll. This server allows a user to login, and then access the webconnector functions, Database access, and basically everything else inside the server.

Existing samples

  • see project csharp\ICT\Testing\MFinance\server\Gift, which has a simple test for DataAccess and for a WebConnector.