• No results found

Nunit 89 

In document CSharp Handout v1.0 (Page 89-103)

Learning Objectives

After completing this session, you will be able to: ‰ Perform Unit testing using N-Unit

Nunit:

In order to test an application under NUnit, you write test code that is specially annotated using custom Attributes. Your test code contains Assertions, which demonstrate the correct working of the application.

If your application stores settings in Configuration Files, NUnit provides you with the ability to have settings for your test, which are different from those used in production.

In addition to running tests in a single assembly, NUnit provides support for tests organized as Multiple Assemblies and for creating and running tests as NUnit Test Projects.

Assertions

Assertions are central to unit testing in any of the xUnit frameworks, and NUnit is no exception. NUnit provides a rich set of assertions as static methods of the Assert class.

If an assertion fails, the method call does not return and an error is reported. If a test contains multiple assertions any that follow the one that failed will not be executed. For this reason, it's usually best to try for one assertion per test.

Each method may be called without a message, with a simple text message or with a message and arguments. In the last case the message is formatted using the provided text and arguments.

Classic Assert Model

The classic Assert model uses a separate method to express each individual assertion of which it is capable.

Here is a simple assert using the classic model:

StringAssert.AreEqualIgnoringCase( "Hello", myString );

The Assert class provides the most commonly used assertions. Assert methods are grouped as follows: ‰ Equality Asserts ‰ Identity Asserts ‰ Comparison Asserts ‰ Type Asserts ‰ Condition tests

‰ Utility methods

Beyond the basic facilities of Assert, additional assertions are provided by the following classes: ‰ StringAssert

‰ CollectionAssert ‰ FileAssert

Equality Asserts

These methods test whether the two arguments are equal. Overloaded methods are provided for common value types so that languages that do not automatically box values can use them directly.

Assert.AreEqual( int expected, int actual );

Assert.AreEqual( int expected, int actual, string message ); Assert.AreEqual( int expected, int actual, string message, params object[] parms );

Assert.AreEqual( uint expected, uint actual );

Assert.AreEqual( uint expected, uint actual, string message ); Assert.AreEqual( uint expected, uint actual, string message, params object[] parms );

Assert.AreEqual( decimal expected, decimal actual );

Assert.AreEqual( decimal expected, decimal actual, string message ); Assert.AreEqual(decimal expected, decimal act, string message, params object[] parms );

Assert.AreEqual( float expected, float actual, float tolerance ); Assert.AreEqual( float expected, float actual, float tolerance, string message );

Assert.AreEqual( float exptd, float act, float tolera, string msg, params object[] parms );

Assert.AreEqual( double expected, double actual, double tolerance ); Assert.AreEqual( double expected, double actual, double tolerance, string message );

Assert.AreEqual( double exptd, double act, double tolerance, string msg, params object[] parms );

Assert.AreEqual( object expected, object actual );

Assert.AreEqual( object expected, object actual, string message ); Assert.AreEqual( object expected, object actual, string message, params object[] parms );

Assert.AreNotEqual( int expected, int actual );

Assert.AreNotEqual( int expected, int actual, string message, params object[] parms );

Assert.AreNotEqual( long expected, long actual );

Assert.AreNotEqual( long expected, long actual, string message ); Assert.AreNotEqual( long expected, long actual, string message, params object[] parms );

Assert.AreNotEqual( uint expected, uint actual );

Assert.AreNotEqual( uint expected, uint actual, string message ); Assert.AreNotEqual( uint expected, uint actual, string message, params object[] parms );

Assert.AreNotEqual( ulong expected, ulong actual );

Assert.AreNotEqual( ulong expected, ulong actual, string message ); Assert.AreNotEqual( ulong expected, ulong act, string message, params object[] parms );

Assert.AreNotEqual( decimal expected, decimal actual );

Assert.AreNotEqual( decimal expected, decimal actual, string message ); Assert.AreNotEqual( decimal expected, decimal act, string msg, params object[] parms );

Assert.AreNotEqual( float expected, float actual );

Assert.AreNotEqual( float expected, float actual, string message ); Assert.AreNotEqual( float expected, float actual, string message, params object[] parms );

Assert.AreNotEqual( double expected, double actual );

Assert.AreNotEqual( double expected, double actual, string message ); Assert.AreNotEqual( double expected, double act, string msg, params object[] parms );

Assert.AreNotEqual( object expected, object actual );

Assert.AreNotEqual( object expected, object actual, string message ); Assert.AreNotEqual( object expected, object act, string msg, params object[] parms );

Condition Tests

Methods that test a specific condition are named for the condition they test and take the value tested as their first argument and, optionally a message as the second. The following methods are provided:

Assert.IsTrue( bool condition );

Assert.IsTrue( bool condition, string message );

Assert.IsTrue( bool condition, string message, object[] parms );

Assert.IsFalse( bool condition);

Assert.IsFalse( bool condition, string message );

Assert.IsFalse( bool condition, string message, object[] parms );

Assert.IsNull( object anObject );

Assert.IsNull( object anObject, string message );

Assert.IsNull( object anObject, string message, object[] parms );

Assert.IsNotNull( object anObject );

Assert.IsNotNull( object anObject, string message );

Assert.IsNotNull( object anObject, string message, object[] parms );

Assert.IsNaN( double aDouble );

Assert.IsNaN( double aDouble, string message );

Assert.IsNaN( double aDouble, string message, object[] parms );

Assert.IsEmpty( string aString );

Assert.IsEmpty( string aString, string message );

Assert.IsEmpty( string aString, string message, params object[] args );

Assert.IsNotEmpty( string aString );

Assert.IsNotEmpty( string aString, string message );

Assert.IsNotEmpty( string aString, string message, params object[] args );

Assert.IsEmpty( ICollection collection );

Assert.IsEmpty( ICollection collection, string message );

Assert.IsEmpty( ICollection collection, string message, params object[] args );

Assert.IsNotEmpty( ICollection collection );

Assert.IsNotEmpty( ICollection collection, string message ); Assert.IsNotEmpty( ICollection collection, string message, params object[] args );

Assert.AreNotEqual( object expected, object act, string msg, params object[] parms );

Comparisons

The following methods test whether one object is greater than than another. Contrary to the normal order of Asserts, these methods are designed to be read in the "natural" English-language or mathematical order. Thus Assert.Greater( x, y ) asserts that x is greater than y ( x > y ). Assert.Greater( int arg1, int arg2 );

Assert.Greater( int arg1, int arg2, string message );

Assert.Greater( int arg1, int arg2, string message, object[] parms );

Assert.Greater( uint arg1, uint arg2 );

Assert.Greater( uint arg1, uint arg2, string message );

Assert.Greater( uint arg1, uint arg2, string message, object[] parms );

Assert.Greater( long arg1, long arg2 );

Assert.Greater( long arg1, long arg2, string message );

Assert.Greater( long arg1, long arg2, string message, object[] parms );

Assert.Greater( ulong arg1, ulong arg2 );

Assert.Greater( ulong arg1, ulong arg2, string message );

Assert.Greater( ulong arg1, ulong arg2, string message, object[] parms );

Assert.Greater( decimal arg1, decimal arg2 );

Assert.Greater( decimal arg1, decimal arg2, string message );

Assert.Greater( decimal arg1, decimal arg2, string message, object[] parms );

Assert.Greater( double arg1, double arg2 );

Assert.Greater( double arg1, double arg2, string message );

Assert.Greater( double arg1, double arg2, string message, object[] parms );

Assert.Greater( double arg1, double arg2 );

Assert.Greater( double arg1, double arg2, string message );

Assert.Greater( double arg1, double arg2, string message, object[] parms );

Assert.Greater( float arg1, float arg2 );

Assert.Greater( float arg1, float arg2, string message );

Assert.Greater( float arg1, float arg2, string message, object[] parms );

Assert.Greater( IComparable arg1, IComparable arg2 );

Assert.Greater( IComparable arg1, IComparable arg2, string message, object[] parms );

The following methods test whether one object is greater than or equal to another. Contrary to the normal order of Asserts, these methods are designed to be read in the "natural" English-language or mathematical order. Thus Assert.GreaterOrEqual( x, y ) asserts that x is greater than or equal to y ( x >= y ).

Assert.GreaterOrEqual( int arg1, int arg2 );

Assert.GreaterOrEqual( int arg1, int arg2, string message );

Assert.GreaterOrEqual( int arg1, int arg2, string message, object[] parms );

Assert.GreaterOrEqual( uint arg1, uint arg2 );

Assert.GreaterOrEqual( uint arg1, uint arg2, string message );

Assert.GreaterOrEqual( uint arg1, uint arg2, string message, object[] parms );

Assert.GreaterOrEqual( long arg1, long arg2 );

Assert.GreaterOrEqual( long arg1, long arg2, string message );

Assert.GreaterOrEqual( long arg1, long arg2, string message, object[] parms );

Assert.GreaterOrEqual( ulong arg1, ulong arg2 );

Assert.GreaterOrEqual( ulong arg1, ulong arg2, string message );

Assert.GreaterOrEqual( ulong arg1, ulong arg2, string message, object[] parms );

Assert.GreaterOrEqual( decimal arg1, decimal arg2 );

Assert.GreaterOrEqual( decimal arg1, decimal arg2, string message ); Assert.GreaterOrEqual( decimal arg1, decimal arg2, string message, object[] parms );

Assert.GreaterOrEqual( double arg1, double arg2 );

Assert.GreaterOrEqual( double arg1, double arg2, string message ); Assert.GreaterOrEqual( double arg1, double arg2, string message, object[] parms );

Assert.GreaterOrEqual( double arg1, double arg2 );

Assert.GreaterOrEqual( double arg1, double arg2, string message ); Assert.GreaterOrEqual( double arg1, double arg2, string message, object[] parms );

Assert.GreaterOrEqual( float arg1, float arg2 );

Assert.GreaterOrEqual( float arg1, float arg2, string message );

Assert.GreaterOrEqual( IComparable arg1, IComparable arg2 ); Assert.GreaterOrEqual( IComparable arg1, IComparable arg2, string message );

Assert.GreaterOrEqual( IComparable arg1, IComparable arg2, string message, object[] parms );

The following methods test whether one object is less than than another. Contrary to the normal order of Asserts, these methods are designed to be read in the "natural" English-language or mathematical order. Thus Assert.Less( x, y ) asserts that x is less than y ( x < y ).

Assert.Less( int arg1, int arg2 );

Assert.Less( int arg1, int arg2, string message );

Assert.Less( int arg1, int arg2, string message, object[] parms );

Assert.Less( uint arg1, uint arg2 );

Assert.Less( uint arg1, uint arg2, string message );

Assert.Less( uint arg1, uint arg2, string message, object[] parms );

Assert.Less( long arg1, long arg2 );

Assert.Less( long arg1, long arg2, string message );

Assert.Less( long arg1, long arg2, string message, object[] parms );

Assert.Less( ulong arg1, ulong arg2 );

Assert.Less( ulong arg1, ulong arg2, string message );

Assert.Less( ulong arg1, ulong arg2, string message, object[] parms );

Assert.Less( decimal arg1, decimal arg2 );

Assert.Less( decimal arg1, decimal arg2, string message );

Assert.Less( decimal arg1, decimal arg2, string message, object[] parms );

Assert.Less( double arg1, double arg2 );

Assert.Less( double arg1, double arg2, string message );

Assert.Less( double arg1, double arg2, string message, object[] parms );

Assert.Less( float arg1, float arg2 );

Assert.Less( float arg1, float arg2, string message );

Assert.Less( float arg1, float arg2, string message, object[] parms );

Assert.Less( IComparable arg1, IComparable arg2 );

Assert.Less( IComparable arg1, IComparable arg2, string message ); Assert.Less( IComparable arg1, IComparable arg2, string message, object[] parms );

The following methods test whether one object is less than or equal to another. Contrary to the normal order of Asserts, these methods are designed to be read in the "natural" English-language or mathematical order. Thus Assert.LessOrEqual( x, y ) asserts that x is less than or equal to y ( x <= y ).

Assert.LessOrEqual( int arg1, int arg2 );

Assert.LessOrEqual( int arg1, int arg2, string message );

Assert.LessOrEqual( int arg1, int arg2, string message, object[] parms );

Assert.LessOrEqual( uint arg1, uint arg2 );

Assert.LessOrEqual( uint arg1, uint arg2, string message );

Assert.LessOrEqual( uint arg1, uint arg2, string message, object[] parms );

Assert.LessOrEqual( long arg1, long arg2 );

Assert.LessOrEqual( long arg1, long arg2, string message );

Assert.LessOrEqual( long arg1, long arg2, string message, object[] parms );

Assert.LessOrEqual( ulong arg1, ulong arg2 );

Assert.LessOrEqual( ulong arg1, ulong arg2, string message );

Assert.LessOrEqual( ulong arg1, ulong arg2, string message, object[] parms );

Assert.LessOrEqual( decimal arg1, decimal arg2 );

Assert.LessOrEqual( decimal arg1, decimal arg2, string message );

Assert.LessOrEqual( decimal arg1, decimal arg2, string message, object[] parms );

Assert.LessOrEqual( double arg1, double arg2 );

Assert.LessOrEqual( double arg1, double arg2, string message );

Assert.LessOrEqual( double arg1, double arg2, string message, object[] parms );

Assert.LessOrEqual( float arg1, float arg2 );

Assert.LessOrEqual( float arg1, float arg2, string message );

Assert.LessOrEqual( float arg1, float arg2, string message, object[] parms );

Assert.LessOrEqual( IComparable arg1, IComparable arg2 );

Assert.LessOrEqual( IComparable arg1, IComparable arg2, string message );

Assert.LessOrEqual( IComparable arg1, IComparable arg2, string message, object[] parms );

Attributes

Version 1 of NUnit used the classic approach to identifying tests based on inheritance and naming conventions. From version 2.0 on, NUnit has used custom attributes for this purpose. Because NUnit test fixtures do not inherit from a framework class, the developer is free to use inheritance in other ways. And because there is no arbitrary convention for naming tests, the choice of names can be entirely oriented toward communicating the purpose of the test. All NUnit attributes are contained in the NUnit.Framework namespace. Each source file that contains tests must include a using statement for that namespace and the project must reference the framework assembly, nunit.framework.dll.

TestFixtureAttribute

This is the attribute that marks a class that contains tests and, optionally, setup or teardown methods. There are a few restrictions on a class that is used as a test fixture.

‰ It must be a publicly exported type. ‰ It must have not been abstract. ‰ It must have a default constructor

‰ It must have no more than one of each of the following method types: SetUp, TearDown, TestFixtureSetUp and TestFixtureTearDown.

If any of these restrictions are violated, then the class will be shown as a non-runnable test fixture, and will turn yellow in the GUI if you attempt to run it.

using System;

using NUnit.Framework; namespace NUnit.Tests {

[TestFixture]

public class SuccessTests {

// ... }

}

TestFixtureSetUpAttribute

This attribute is used inside a TestFixture to provide a single set of functions that are performed once prior to executing any of the tests in the fixture. A TestFixture can have only one

TestFixtureSetUp method. If more than one is defined the TestFixture will compile successfully but its tests will not run.

using System;

using NUnit.Framework; namespace NUnit.Tests {

[TestFixture]

public class SuccessTests {

{ /* ... */ }

[TestFixtureTearDown] public void Dispose() { /* ... */ }

[Test] public void Add() { /* ... */ }

} }

TestFixtureTearDownAttribute

This attribute is used inside a TestFixture to provide a single set of functions that are performed once after all tests are completed. A TestFixture can have only one TestFixtureTearDown method. If more than one is defined the TestFixture will compile successfully but its tests will not run.

So long as any TestFixtureSetUp method runs without error, the TestFixtureTearDown method is guaranteed to run. It will not run if a TestFixtureSetUp method fails or throws an exception.

TestAttribute

The Test attribute marks a specific method inside a class that has already been marked as a TestFixture, as a test method. For backwards compatibility with previous versions of Nunit a test method will also be found if the first 4 letters are "test" regardless of case.

The signature for a test method is defined as follows: public void MethodName()

Note that there must be no parameters. If the programmer marks a test method that does not have the correct signature, then it will not be run and it will appear in the Test Not Run area in the UI that ran the program.

using System; using NUnit.Framework; namespace NUnit.Tests { using System; using NUnit.Framework; [TestFixture]

public class SuccessTests {

[Test] public void Add() { /* ... */ }

public void TestSubtract()

{ /* backwards compatibility */ } }

Configuration Files

NUnit uses configuration files for the test runner executable – either nunit-console.exe or

nunitgui.exe – as well as for the tests being run. Only settings that pertain to NUnit itself should be in the nunit-console.exe.config and nunit-gui.exe.config, while those that pertain to your own application and tests should be in a separate configuration file.

NUnit Configuration Files

One main purpose of the nunit-console and nunit-gui config files is to allow NUnit to run with various versions of the .NET framework. NUnit is built using versions 1.1 and 2.0 of the framework. The two builds are provided as separate downloads and either build can be made to run against other versions of the CLR.

As delivered, the section of each config file is commented out, causing NUnit to run with the version of .NET used to build it. If you uncomment the section, the entries there control the order in which alternate framework versions are selected.

Test Configuration File

When a configuration file is used to provide settings or to control the environment in which a test is run, specific naming conventions must be followed.

If a single assembly is being loaded, then the configuration file is given the name of the assembly file with the config extension. For example, the configuration file used to run nunit.tests.dll must be named nunit.tests.dll.config and located in the same directory as the dll.

f an NUnit project is being loaded into a single AppDomain, the configuration file uses the name of the project file with the extension changed to config. For example, the project AllTests.nunit would require a configuration file named AllTests.config, located in the same directory as AllTests.nunit. The same rule is followed when loading Visual Studio projects or solutions.

Generally, you should be able to simply copy your application config file and rename it as described above. However, see the next section if you wish to run tests compiled for an earlier version of NUnit.

Multiple-Assembly Support

As version 2.1, NUnit has allowed loading suites of tests from multiple assemblies in both the console and GUI runners. This may be done on an adhoc basis or by creating NUnit test projects saved as files of type '.nunit'. In either case, a top-level suite is constructed, which contains the root suite for each assembly. Tests are run and reported just as for a single assembly.

Adhoc Usage

Using the console runner, multiple assemblies may be run simply by specifying their names on the command line.

The GUI runner does not support specifying multiple assemblies on the command-line. However, you can load a single assembly and then use the Project menu to add additional assemblies. Additionally, you can drag multiple assemblies to the tree view pane, in which case they will replace any assemblies already loaded.

NUnit Test Projects

Running tests from multiple assemblies is facilitated by the use of NUnit test projects. These are files with the extension .nunit containing information about the assemblies to be loaded. The following is an example of a hypothetical test project file:

<NUnitProject> <Settings activeconfig="Debug"/> <Config name="Debug"> <assembly path="LibraryCore\bin\Debug\Library.dll"/> <assembly path="LibraryUI\bin\Debug\LibraryUI.dll"/> </Config> <Config name="Release"> <assembly path="LibraryCore\bin\Release\Library.dll"/> <assembly path="LibraryUI\bin\Release\LibraryUI.dll"/> </Config> </NUnitProject>

This project contains two configurations, each of which contains two assemblies. The Debug configuration is currently active. By default, the assemblies will be loaded using the directory containing this file as the ApplicationBase. The PrivateBinPath will be set automatically to LibraryCore\bin\Debug;LibraryUI\bin\Debug or to the corresonding release path. XML attributes are used to specify non-default values for the ApplicationBase, Configuration File and

PrivateBinPath. The Project Editor may be used to create or modify NUnit projects.

Even when you are running a single test assembly, NUnit creates an internal project to contain that assembly. If you are using the gui, you can save this project, edit it, add additional assemblies, etc. Note that the gui does not display the internal project unless you add assemblies or modify it in some other way.

If you use Visual Studio Support to load Visual Studio .Net project or solution files, NUnit converts them to Test projects internally. As with other internal projects, these test projects are not saved automatically but may be saved by use of the File menu.

Loading and Running

In the past, test writers have been able to rely on the current directory being set to the directory containing the single loaded assembly. For the purpose of compatibility, NUnit continues to set the current directory to the directory containing each assembly whenever any test from that assembly is run.

Additionally, because some assemblies may rely on unmanaged dlls in the same directory, the current directory is also set to that of the assembly at the time the assembly is loaded. However, in cases where multiple assemblies reference the same unmanaged assembly, this may not be sufficient and the user may need to place the directory containing the unmanaged dll on the path.

Visual Studio Support

Visual Studio support in this release is a sort of “poor man’s integration.” We have implemented a number of features while avoiding any that would require using an Addin or otherwise interacting

Running From Within Visual Studio

The most convenient way to do this is to set up a custom tool entry specifying the path to NUnit- gui.exe as the command. For a C# project, you may wish to use $(TargetPath) for the arguments and $(TargetDir) for the initial directory. If you would like to debug your tests, use the Visual Studio Debug | Processes… menu item to attach to nunit-gui.exe after starting it and set breakpoints in your test code as desired before running the tests.

Using Console Interface to Debug Applications

When the nunit-console program is run in debug mode under Visual Studio, it detects that it is running in this mode and sends output to the Visual Studio output window. Output is formatted so that double clicking any error or failure entries opens the appropriate test file at the location where the failure was detected.

Opening Visual Studio Projects

When Visual Studio support is enabled, the File Open dialog displays the following supported Visual Studio project types: C#, VB.Net, J# and C++. The project file is read and the configurations and output assembly locations are identified. Since the project files do not contain information about the most recently opened configuration, the output assembly for the first configuration found (usually Debug) is loaded in the GUI. The tree shows the project as the toplevel node with the assembly shown as its descendant.

When tests are run for a Visual studio project, they run just as if the output assembly had been loaded with one exception. The default location for the config file is the directory containing the project file and it’s default name is the same as the project file with an extension of .config. For example, the following command would load the tests in the nunit.tests assembly using the configuration file nunit.tests.dll.config located in the same directory as the dll.

nunit-gui.exe nunit.tests.dll

On the other hand, the following command would load the tests using the configuration file nunit.tests.config located in the same directory as the csproj file.

nunit-gui.exe nunit.tests.csproj

The same consideration applies to running tests using the console runner.

Opening Visual Studio Solutions

When Visual Studio support is enabled, solution files may be opened as well. All the output assemblies from contained projects of the types supported will be loaded in the tree. In the case where all contained projects are located in the subdirectories beneath the solution, it will be possible to load and run tests using this method directly.

When a solution contains projects located elsewhere in the file system, it may not be possible to run the tests – although the solution will generally load without problem. In this case, the Project Editor should be use to modify and save the NUnit test project so that there is all referenced assemblies are located in or beneath the application base directory.

Adding Visual Studio Projects to the Open Test Project

When Visual Studio support is enabled, the Project menu contains an active entry to add a VS project to the loaded project. The output assembly will be added for each of the configurations specified in the VS project.

Summary

‰ NUnit provides a powerful framework for Unit Testing.

‰ Synopsis on Unit testing and how it can be utilized for appropriate exception handling,

In document CSharp Handout v1.0 (Page 89-103)