Coding

Implementing the examples

This page describes coding fixtures in C#. Click the toggle buttons above to choose other options.

Overview

Concordion fixtures find commands in the instrumented specification and use them to verify the system under test.

Concordion is a test runner that can invoke your application code directly:

Fixture calling application code directly

It can also drive the interfaces of your deployed application:

Fixture calling driver calling deployed application

It is good practice to create a separate driver layer for the code that drives your application interface, keeping the runner free of driver logic and the driver layer free of test assertions. Other libraries are required for the driver layer, such as Selenium WebDriver for web applications etc. Any .NET library can be used with Concordion, providing a lot of flexibility in how you use it. See the FAQ for further detail.

Project Structure

Dependencies

Version 3.5 or higher of the .NET framework must be used as target framework in the project that contains your Concordion.NET fixture classes.

Concordion.NET requires a number of libraries to be present, including Concordion, NUnit, XOM and OGNL libraries.

The best way to manage these dependencies is to use NuGet. See the download page for details.

As an alternative, you can download the full distribution from the download page. After extracting the files, you must add references to all the downloaded libraries to the project.

Assembly Info

Add the attribute [assembly: RequiredAddin("ConcordionNUnitAddin")] to the AssemblyInfo.cs of your project. This tells NUnit that the Concordion-NUnit-Addin is required to run your Concordion.NET tests.

Locating the Specification

The fixture must be in the same namespace as the specification, where the namespace of the fixture is composed from the default namespace of the project plus the path to the specification.

For example, in the tutorial, the fixture with a namespace of Marketing.Mailshot.Completed:

Fixture with namespace set to Marketing.Mailshot.Completed

uses a specification with its namespace derived by taking the default namespace for the project - which is set to Marketing.Mailshot:

Project properties showing default namespace

and appending the Completed folder that the specification is in:

Folder structure showing specification in the Completed folder

The name of the fixture class and the specification share the same base name. The fixture has an optional suffix of “Fixture” or “Test” - for example, the fixture for the “SplittingNames.html” specification could be named “SplittingNames.cs”, “SplittingNamesFixture.cs” or “SplittingNamesTest.cs”.

As an alternative, you can configure the BaseInputDirectory to specify the location of your specification documents.

Including the Specification in the DLL

In order for the specification to be found, it must be included in your DLL file: In Visual Studio, open the properties for the specification and set the value “Embedded Resource” on the property “Build Action”:

Properties for specification

Setup your NUnit Runner

Finally, if you haven’t already added the current version of Concordion.NUnit.dll to your NUnit addins folder, you will need to install the Concordion NUnit dll as a NUnit addin.

Fixture classes

Concordion fixtures use the NUnit library, with a Concordion addin. Fixtures must declare a class-level ConcordionTest attribute from the Concordion.NET.Integration namespace:

using Concordion.NET.Integration;

namespace Marketing.Mailshot.Initial
{
    [ConcordionTest]
    public class SplittingNamesFixture
    {
    }
}

A fixture class is required for each specification.

Unlike NUnit, we don’t add a [Test] attribute to methods. Instead, the tests are determined from the specification. The specification is run as a single NUnit test.

Fixture methods

Parameter types

Methods in Concordion fixtures can take the following parameter types:

  • Numeric types (int, long, float, double, decimal)
  • string
  • bool

When executed from a Concordion specification, Concordion will automatically convert the value to the parameter type. Boolean values must be specified as true or false in the specification.

Return types

Methods can return void, a primitive or an Object.

Returning a Dictionary result

As described in the tutorial, to check more than one result of a behaviour, you can return an Object from the execute command. An alternative is to return a Dictionary object, for example:

public Dictionary<String, String> Split(string fullName)
{
    string[] words = fullName.Split(' ');
    Dictionary<String, String> result = new Dictionary<String, String>();
    result.Add("firstName", words[0]);
    result.Add("lastName", words[1]);
    return result;
}

This is particularly useful when calling existing methods that return Dictionary objects.

Implementation status

To allow you to include specifications in the build before they have been fully implemented, you can annotate a fixture class with the NUnit IgnoreAttribute. When you add the [Ignore] attribute at the top of your fixture class, NUnit will not run this particular active specification. Instead, the test will be marked yellow and added to your test reports. This helps to ensure that the test will not be forgotten in future.

Field Scope

Concordion encourages you to keep your examples completely independent of each other. This allows individual examples to be run in isolation. It also makes the specification easier to follow when you can read examples in isolation.

Fixture Setup Methods

To run a method prior to executing the tests in the specification, mark that method with the NUnit attribute [TestFixtureSetUp]. See the NUnit documentation for further details.

Configuration Options

Concordion.NET is configured using a configuration file with the same name as the DLL file, but with the suffix .dll replaced by .config. The config file has to be located in the same directory as your DLL file to be loaded by Concordion.NET.

The following features can be configured:

Adding Extensions

Extensions are added to Concordion fixtures by:

  • Adding the [Extensions] attribute to the fixture class. This attribute is parameterised with a list of extension, and/or extension factory, classes to be installed.

For example:

[Extensions(typeof(LoggingTooltipExtension.class), typeof(TimestampFormatExtension.class))]
public class MyTest {
...
  • Or adding the [Extension] attribute to fields in the fixture class. This allows the extensions to be configured per class instance. For example:
...
[Extension]
public ConcordionExtension extension = new ScreenshotExtension().SetScreenshotTaker(camera);
...
  • Or by adding <Extension> entries to the <ConcordionExtensions> section of the configuration file with extension, and/or extension factory, classes. For example:
<ConcordionExtensions>
    <Extension assembly="LoggingTooltipExtension" type="Ext.LoggingTooltipExtension" />
</ConcordionExtensions>

For further details see the extension configuration specification.

Creating an extension

The Extensions API allows you to add functionality to Concordion, for example implementing new commands, listening to events, or modifying the Concordion output.

A dedicated section of the executable specifications describe the extensions API of Concordion.NET. The fixture classes demonstrate how to use the extensions API.

See also the extensions of the Java version of Concordion for examples what can be achieved with the help of the extensions API.

Extensions must implement the ConcordionExtension interface, which allows extensions to hook into the Concordion.NET build phase through the ConcordionExtender interface.

Example: Adding custom CSS

Amongst other features, the ConcordionExtender interface provide a means for adding CSS, JavaScript or arbitrary resources to the Concordion.NET output folder.

The following example extension copies /my_concordion.css from the classpath to the root folder of the Concordion.NET output, and links to it from the Concordion.NET output HTML.

using org.concordion.api.extension;

namespace Com.Acme
{
    public class MyCssExtension : ConcordionExtension {
        public void addTo(ConcordionExtender concordionExtender) {
            concordionExtender.withLinkedCSS("/my_concordion.css",
                new Resource("/my_concordion.css"));
        }
    }
}

Note: if you have already declared a link to the CSS file in your HTML, you should use concordionExtender.withResource() rather than concordionExtender.withLinkedCSS() to avoid a duplicate declaration.

If you’d prefer to embed the CSS in the HTML, rather than link it, use concordionExtender.withEmbeddedCSS(). Similar methods exist for including JavaScript in the output, or you can use withResource() to copy images or other resources to the output.