Search And Destroy

Look out honey, ’cause I’m using technology!

Archive for the ‘Testing Tool Tour’ Category

Testing Tool Tour : QuickNet Preview

Posted by kilfour on August 2, 2009


Update 24/12/2009

The information (especially syntax) in this post is quite out of date, please visit the projects home page on google code for links to up to date examples or use the QuickNet category link on this blog.
The principles in the article are still valid, although these days I would probably rewrite the multply spec like so :

new Spec(() => Ensure.Equal( input.First, output / input.Second )

in order to avoid the ‘you’re duplicating business logic’-argument.
I’ve gotten better at coming up with specs lately ;-) .


Recently I had the enjoyable experience of working on a dot net 3.5 project, instead of 2.0, as was the case for the previous year and a half. As a result I’ve been coding quite a bit lately, not downloading IDE’s and testers in order to take them for a spin.
I was planning on taking the more historically correct road and tour JUnit next. But in view of these recent developments, I opted for this QuickNet tour instead.

QuickNet is my poor man’s c# implementation of a property based tester for dot net 3.5.
I tend to call it property based as I’ve seen John Hughes’s QuviQ been described as such, and that, and QuickCheck (from the Haskell language) are what inspired QuickNet. Although inspired might be an overstatement. I just really quickly needed a better way to organize my unit/integration tests as they were getting too hard to maintain. The ideas from above mentioned testing tools seemed just what I needed.

Taking it for a spin : (using the cannonical calculator example)
You need dot net 3.5 and a MS Visual Studio, which pretty much means : get a job in the computer industry, and then you need wait for an alpha release of QuickNet ;-) .

Our first Calculator C# implementation :

public class Calculator
{
    public int Multiply(int a, int b)
    {
        return 6;
    }
}

And the first tests :

[TestFixture]
public class TheThirdFixture
{
    [Test]
    public void UnitTestCalculatorMultiply()
    {
        Assert.AreEqual(6, new Calculator().Multiply(3,2));
        Assert.AreEqual(15, new Calculator().Multiply(5,3));
    }

    [Test]
    public void CalculatorTest()
    {
        IntGenerator gen = new IntGenerator(0, 200);
        new TestRun()
            .AddTransition(new Transition<Input<int, int>, int>()
            {
                GenerateInput = 
                    () => new Input 
                                { 
                                    ParamOne = gen.Value, 
                                    ParamTwo = gen.Value 
                                },
                Execute = 
                    input => new Calculator().Multiply(input.ParamOne, input.ParamTwo))
            }
            .RegisterProperty(( input, output ) => new Property(() =>
                QnAssert.AreEqual( input.ParamOne * input.ParamTwo, output ))))
            .Verify()
            .ThrowTestFailedExceptionIfAnyOnePropertyFailed()
            .ReportPropertiesTested(new ConsoleReporter());
        }
    }
}

I included an NUnit test with two asserts. The first one will pass. The second assert fails as our implementation is buggy.

The QuickNet test also fails. Let’s see how it’s defined.
The local IntGenerator variable is an instance of a QuickNet helper class that gets a random int.
Next we create a TestRun, to which we add the following Transition.

new Transition<Input<int, int>, int>()

The types were passing in here are a type definition of Input and Output members of the transition.
The GenerateInput (lambda) member of the transition uses the IntGenerator to obtain two random ints.
The Execute (lambda) member of the transition uses the values from GenerateInput, calls multiply on the calculator and returns an int result.
We then register a property on this transition. A property receives a transition’s input and output and asserts something. This particular property states the the output of the transition should equal the first parameter of it’s input multiplied by the second parameter of it’s input.
We then call Verify on the TestRun to assert all our registered properties, call ThrowTestFailedExceptionIfAnyOnePropertyFailed to make the NUnit test fail if QuickCheck fails, and in case that it passes we report some run details to the console.

We correct our buggy method to correctly return a * b and both tests pass.

A Trickier Bug
Even though QuickNet originated out of a need for less code, some of you might have noticed that the QuickNet test is quite verbose compared to the NUnit test. So what’s the point ?
Suppose some work get’s done on our calculator and the following is implemented :

public class Calculator
{
    private int count = 0;
    public int Multiply(int a, int b)
    {
        count++;
        if(count == 10)
            throw new Exception()
        return a * b;
    }
}

Both tests will still pass.
At some point an unfortunate user of this code tries multiply ten times, reports the bug and we modify our tests to demonstrate it.
For the NUnit part : add the following test :

[Test]
public void UnitTestCalculatorMultiplyManyTimes()
{
    Calculator calculator = new Calculator();
    for(int i = 0; i < 100; i++)
    {
          Assert.AreEqual(6, calculator.Multiply(3,2));
    }
}

For the QuickNet test :
Declare a local Calculator below the IntGenerator and instantiate it.
Modify the lambda to use this local instance instead of calling new.
Just run it a hundred times or more by changing the call to the testrun constructor to

new TestRun(1, 100) 

Both test will now fail. We had to add an NUnit test to find the bug. QuickNet had to be tweaked.

Even Trickier
Now we need to implement Divide.
For NUnit we add the following test :

[Test]
public void UnitTestCalculatorDivide()
{
    Calculator calculator = new Calculator();
    Assert.AreEqual(3, calculator.Divide(6,2));
    Assert.AreEqual(4, calculator.Divide(16,4));
}

The QuickNet test needs a new Transition for this. The full test looks like this :

[TestFixture]
public class TheThirdFixture
{
    [Test]
    public void CalculatorTest()
    {
        Calculator calculator = new Calculator();
        CalculatorInputGenerator gen = new CalculatorInputGenerator();
        new TestRun(1,100)
            .AddTransition(new Transition<Input<int, int>, int>()
            {
                GenerateInput = () => gen.Value,
                Execute = input => calculator.Multiply(input.ParamOne, input.ParamTwo))
            }
            .RegisterProperty(( input, output ) => new Property(() =>
                QnAssert.AreEqual( input.ParamOne * input.ParamTwo, output ))))
            .AddTransition(new Transition<Input<int, int>, int>()
            {
                GenerateInput = () => gen.Value,
                Execute = input => calculator.Divide(input.ParamOne, input.ParamTwo))
            }
            .RegisterProperty(( input, output ) => new Property(() =>
                QnAssert.AreEqual( input.ParamOne / input.ParamTwo, output ))))
            .Verify()
            .ThrowTestFailedExceptionIfAnyOnePropertyFailed()
            .ReportPropertiesTested(new ConsoleReporter());
        }
    }
}

Now someone implemented this as such :

public class Calculator
{
    private string bug = "";
    public int Multiply(int a, int b)
    {
        bug += "1";
        if(bug == "112121")
           throw new Exception();
        return a * b;
    }
    public int Divide(int a, int b)
    {
        bug += "2";
        return a / b;
    }
}

The NUnit tests will pass. QuickNet fails.
For NUnit :
Add a test.

[Test]
public void UnitTestCalculatorDivide()
{
    Calculator calculator = new Calculator();
    Assert.AreEqual(6, calculator.Multiply(3,2));
    Assert.AreEqual(6, calculator.Multiply(3,2));
    Assert.AreEqual(3, calculator.Divide(6,2));
    Assert.AreEqual(6, calculator.Multiply(3,2));
    Assert.AreEqual(4, calculator.Divide(16,4));
    Assert.AreEqual(6, calculator.Multiply(3,2));
}

Fix the bug.

For QuickNet : Just fix the bug.

Bonus Bugs
As I was working out the simple example, QuickNet pointed out to me that division by zero throws an exception. Just setting the TestRun constructor to (1, 5000) fails it every time. In NUnit we would need another test. Quicknet needs a new property, and a precondition on the existing one.

Posted in Property Based Testing, QuickNet, Testing Tool Tour | Tagged: , , | 6 Comments »

Testing Tool Tour : SUnit

Posted by kilfour on June 24, 2009

One of the stranger phenomena in developer land is the shocking display of historical ignorance. It is as if you’re building an airplane and don’t know who the Wright brothers were. Or you’re a musician and you’ve never heard of Elvis. Even people with an education in software engineering or something similar, coming straight out of school seem to be blissfully ignorant when it comes down to the history of things. It is said that one should learn from one’s mistakes, but it’s much more fun to learn from other peoples’s trials and tribulations in my opinion. So instead of pushing forward, let’s not be an artist, let’s look back.

Self-testing code isn’t exactly new. Ever since programs started becoming bigger than the machines they had to be executed on, there have been lazy but clever programmers that applied the principal of self testing code in order to alleviate their workload. I have seen quite a bit of ancient ansi-c code over the years and some of it (not enough though) had some form of automated testing going on. Sometimes by (ab)using the ASSERT macro, sometimes by using a scripting language, etc… IBM’s OS/400 operating systems project developed between 1992 to 1994 contained 2 million lines of code. Half of that was (non-shipped) test code. In his book The C++ Programming Language (Special Edition), Bjarne Stroustrup describes a technique consisting out of using an Invariant method for each class. Martin Fowler’s Refactoring contains a passage where he describes getting started with automated testing after the OOPSLA ’92 event.  In december 98 ‘Kent Beck’s Guide to Better Smalltalk’ contained a chapter on a formalized way of testing. The (widely used) link to the original paper on Ron Jeffries xprogramming site does not seem to work anymore but I found a copy right here.

I’ll just quote the first paragraph :

Smalltalk has suffered because it lacked a testing culture. This column describes a simple testing strategy and a framework to support it. The testing strategy and framework are not intended to be complete solutions, but rather a starting point from which industrial strength tools and procedures can be constructed.

This statement led to SmallUnit, and from version 2.0 on SUnit, the mother of any xUnit testing tool. So the architecture of SUnit will look remarkably familiar to any one using NUnit, MSTest, JUnit, … It has a fixture that initializes state and/or releases resources (subclasses of TestCase) and holds one or more single units of testing (the test methods), a group of fixtures can be run as a suite, suites which are composites (TestCases being the leaves), very familiar indeed.

Taking it for a Spin (using the cannonical calculator example)

You need a smalltalk environment obviously. I use squeak for presentation purposes, amongst other things, and with it’s platform independency and one-click install feature, I think it’s the fastest way to try out SUnit. Get the latest squeak release for your platform from the download box on the squeak home page. Unpack the archive and drag the image file onto the virtual machine application. You should now be looking at this :

SqueakStartup

Grab a browser from the Tools flap.

System Browser

Right click the category pane of the system browser and choose add item in the context menu. Add a Calculator-Tests category. With the newly created category selected, the code pane shows the following template code :

Object subclass: #NameOfSubclass
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Calculator-Tests'
Object subclass: #NameOfSubclass
instanceVariableNames: ”
classVariableNames: ”
poolDictionaries: ”
category: ‘Calculator-Tests’

Change this to the following in order to create a class which will contain our tests :

TestCase subclass: #CalculatorTesting
    instanceVariableNames: 'calculator'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Calculator-Tests'

Accepting the code can be done through the context-menu or hotkeys. Selecting an element in the message category pane shows the following template code in the code pane :

message selector and argument names
    "comment stating purpose of message"
    | temporary variable names |
    statements

Change this to following in order to define a setup method, which will be run before running each test defined in this class.

setUp
    "Creates a Calculator object"
    calculator := Calculator new.

Trying to accept this code will pop up a menu telling you that Calculator is an unknown variable. Choose the ‘define new class’ option. When asked for a category, provide one. For example : ‘Calculator-Implementation’. Just accept the proposed definition which should look like this :

Object subclass: #Calculator
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Calculator-Implementation'

Go back to the CalculatorTesting class and add the following test method :


testMultiply
    self assert: (calculator multiply: 2 with: 3) = 6.


Trying to accept this code will pop up an unknown selector message. Just confirm this by selecting the first option from the list. Drag an SUnit test runner window from the tool flap, select the Calculator-Tests category and hit the 'Run Selected' button.

Test Runner Red

Clicking the name of the failing tests opens up a debugger which quickly shows that the test is failing because calculator does not have an multiply: with: method. So add this to the calculator like so :

multiply: a with: b
    ^ 6.

Run the test in SUnit and all turns green. Add another test.


testMultiply2
    self assert: (calculator multiply: 3 with: 5) = 15.


Run the test in SUnit and things turns yellow, signaling an assertion failed. Correct the multiply: with: method.

multiply: a with: b
    ^ a * b.

Run the test in SUnit and all turns green.

Test Runner Green

I really like this one, very easy to use. There are some naming conventions to keep in mind, but that's not a big issue for me. The simplicity of the idea keeps this thing beautifull, even until today.

Posted in Testing Tool Tour | Tagged: , , , , | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.