Skip to content

Short Sample

gerardMurphy edited this page May 18, 2014 · 2 revisions

Let's build some test strings to feed to a very simple calculator.

This calculator can do arithmetic using binary operators - addition, subtraction, multiplication and division.

It can't do unary negation yet and it doesn't understand operator precedence either - read on and you'll see a more complete example, but for now let's keep it nice and easy.

So we can hit it with:-

"2"					==> "2"
"2 + 1"				==> "3"
"0 - 2"				==> "-2"
"1 + (2 * 2)"		==> "5"

Rather than get distracted with implementing the calculator and verifying expectations, let's just print out the test strings...

[TestFixture]
internal class TestBinaryOperatorExpressions
{
    private static readonly ITypedFactory<Char> BinaryOperatorFactory =
        TestVariable.Create(new[] {'+', '-', '*', '/'});

    private static readonly ITypedFactory<String> ConstantFactory =
        TestVariable.Create(new[] {"0", "1", "2"});

    private static ITypedFactory<String> BuildExpressionFactoryRecursively()
    {
        var subexpressionFactory =
            Interleaving.Create(new[]
            {
                ConstantFactory,
                Synthesis.Create(Deferral.Create(BuildExpressionFactoryRecursively),
                    expression => String.Format("({0})", expression))
            });

        var binaryOperatorExpressionFactory = Synthesis.Create(subexpressionFactory,
            BinaryOperatorFactory, subexpressionFactory,
            (lhsOperand, binaryOperator, rhsOperand) =>
                String.Format("{0} {1} {2}", lhsOperand, binaryOperator, rhsOperand));

        return
            Interleaving.Create(new[]
            {ConstantFactory, binaryOperatorExpressionFactory});
    }

    [Test]
    public void FireUpBinaryOperatorExpressions()
    {
        const Int32 maximumDepth = 2;

        var expressionFactory =
            BuildExpressionFactoryRecursively().WithDeferralBudgetOf(maximumDepth);

        const Int32 strength = 2;

        var numberOfTestCasesExercised =
            expressionFactory.ExecuteParameterisedUnitTestForAllTestCases(strength,
                (testCase => Console.Out.WriteLine(testCase)));
        Console.Out.WriteLine("Exercised {0} test cases.", numberOfTestCasesExercised);
    }
}

Running this will print out progressively more complex test strings:-

0 + 0
2 * 1
1 / 1
2 - 1
0 / 1
1 - 0
0 * 2
2 / 0
0 - 2
1 / 2
1 + 1
1 * 0
2 + 2
0
1
2
0 + (1 - 2)
(1 / 2) - 2
(2 + 0) + (0 - 0)
0 * (2 / 1)
(0 - 1) + (2)
(0) * (0 - 1)
etc...

Look carefully at the start - you will see that for any combination of the left hand number and the operator, or the operator and the right hand number, or the left and right hand number, the generated sequence covers it. This is because we set the strength to be 2 - so any pair of items that can be combined in our resulting test case will be covered.

Note how the sequence gets more complex overall, but jumps around various possibilities within each band of complexity - NTestCaseBuilder tries to decorrelate test cases so that they don't clump together like this...

0
1
2
0 + 0
0 + 1
0 + 2
0 * 0
0 * 1
0 * 2

... you can see why this might not be a good idea if we are waiting to see if 1 / 0 blows up - and consider the likes of 2 / (2 / (1 - 1))!

Clone this wiki locally