Thursday, May 28, 2009

Your First Concordion.Net Project (Part 4)

More Specifications!

Part 1Part 2Part 3Part 5

In the previous post we got our project set up and added the first specification.  The sad part was it didn’t really do much.  It only acted as a gateway into our other specifications.  Let’s add something a bit juicier!

In the gateway specification document (Calculator.html) we put a link to an Operations.html specification.  Let’s add that now.  Remember to add the .html and class file then set the properties on the .html file as per the gateway specification and set up the fixture just like the CalculatorTest class.

Calculator.Sample

The content of Operations.html should resemble this when finished

Calculator.Sample.8

Now we have a document describing the various operations that we can perform.  So let’s add two more specifications: one for the arithmetic and one for the trigonometric.  Your project should now look like this:

Calculator.Sample.9

Did you remember to set the .html and .cs files up like the others? I hope so … otherwise you’re in for some heartache :-)

Arithmetic Operations

Let’s add some basic arithmetic operations to our specification: addition, subtraction, multiplication, division.  The specification file is much like our other specification files excepting that it now contains some special markup.  Here is an excerpt from the page’s Multiplication example:

<h3>Example - Multiplication</h3>

<p>
    The result of <b concordion:set="#firstOperand">2</b> * <b concordion:set="#secondOperand">2</b>

    the result will be:
    <b concordion:assertEquals="Multiplication(#firstOperand, #secondOperand)">4</b>
</p>

The rendered html file will resemble this:

Calculator.Sample.10

You can see the source in the included project but the items to note are the concordion:set and the concordion:assertEquals attributes.  concordion:set is used to set a value of a public field or property in the fixture class.  The assertEquals checks the value in the element (the expected value) against the value returned by the operation defined in the concordion:assertEquals attribute.  It is the concordion:assertEquals that will actually turn red or green (maybe yellow, but hopefully not yellow … cross your fingers!)

Creating the fixture

Now that we have a specification, we need some code in the fixture to back it up!  So let’s add some.  Note that this code is going to fail.  True TDD practitioners follow the red-green-refactor methodology so we will try and follow suit.  Our fixture code will look like this:

[ConcordionTest]
public class ArithmeticTest
{
    public long firstOperand;
    public long secondOperand;

    public long Addition(long first, long second)
    {
        return -1;
    }

    public long Subtraction(long first, long second)
    {
        return -1;
    }

    public long Multiplication(long first, long second)
    {
        return -1;
    }

    public long Division(long first, long second)
    {
        return -1;
    }
}

We should now have a complete fixture that should be able to run, albeit with some errors!

Next time we will work on how to run your project with Gallio and produce some results so that we can refactor the above code and turn it into something more meaningful!

5 comments:

  1. Does the runner support throwing out of these methods rather than returning -1? If so, are there any behavioural details as to what your runner will do in response to any particular exception types? (e.g. special support for NotImplementedException that might affect runner output)

    ReplyDelete
  2. @jeremy: you can throw exceptions here but it generates a stack trace in the result and I find it less readable.

    I don't have special support for NotImplementedException yet. If you think it's a good idea enter it as a feature on the project page will you? In the meantime, there are attributes you can decorate your class with. They are described here (as Java annotations, just change them to .NET attributes) http://www.concordion.org/dist/1.3.1/test-output/concordion/spec/concordion/annotation/Annotation.html

    ReplyDelete
  3. Hi,

    What's the purpose of the Calculator.Test project since you are writing your tests in the Calculator.Spec one ?

    ReplyDelete
  4. @Nick: Since this was a simple example I did not fill out the Calculator.Test project for simplicity (and to save my typing hands!).

    Typically, Your *.Spec project is used for integration tests. That is testing the behaviour of one or more classes working in concert together using realistic data. The Calculator.Test project is used for unit testing. That is testing particular classes in isolation perhaps using mocks to mock the integration with other classes.

    I wanted to make it clear that Concordion can be run like a unit testing framework but is not a unit testing framework per se. Rather, it is an acceptance (or behaviour) testing framework. You still need unit tests for the "small stuff" that occurs in a project, like testing input into or output from a particular method. Does that make sense?

    ReplyDelete
  5. Yep it's clear now, thank you.

    ReplyDelete