Today I will introduce a neat design pattern that I use to avoid specifying the parameters and operation more than once. There are two stages; firstly separating out the method logic, and finally making a Verifying API!

Separating the method logic

Remember that each of your tests consist of three distinct aspects

- your scenario
- the expected behaviour
- the logic to compare expected and actual results

Look at the first two lines of your final code from part two. These represent the two scenarios. Notice that on each, the

**input parameters**are specified twice, and the fact that we are using the**add operation**is specified three times!Your original test

assert(
assert(
function addExpected( a, b ) { total = a + b; return [ round(total, 10), remainder(total, 10) ] }

function addResultCheck( expected, actual ) { return expected.sum == actual.sum && expected.rounding == actual.rounding }

**add**ResultCheck(**add**Expected(**2, 4**) ,**add**(**2, 4**)) )**add**ResultCheck(

**add**Expected(

**-2, -4**),

**add**(

**-2, -4**)) )

You have made it simple to update the expected behaviour and comparison code, now you can do the same for the scenario by adding one method as shown in green:

Your fully abstracted test

addVerified( 2, 4 )

addVerified( -2, -4 )

function addVerified( a, b ) { assert( addResultCheck( addExpected( a, b ) , add( a, b )) ) }

function addExpected( a, b ) { total = a + b; return [ round(total, 10), remainder(total, 10) ] }

function addResultCheck( expected, actual ) { return expected.sum == actual.sum && expected.rounding == actual.rounding }

addVerified( -2, -4 )

function addVerified( a, b ) { assert( addResultCheck( addExpected( a, b ) , add( a, b )) ) }

function addExpected( a, b ) { total = a + b; return [ round(total, 10), remainder(total, 10) ] }

function addResultCheck( expected, actual ) { return expected.sum == actual.sum && expected.rounding == actual.rounding }

100% reuse

Congratulations, now all aspects of your test can be reused!

Here is the structure of your test now:

You have split each component on the diagram into a separate method.

Making your own Verifying API

To let your abstraction scale to more tests and more methods to test, you separate the components into separate classes as follows.

Scenario

class CalculatorScenario {

CalculatorVerified verified = new CalculatorVerified()

testAddPositive() {

verified.add( 2, 4 )

}

testAddNegative() {

verified.add( -2, -4)

}

}

Verifying API

class CalculatorVerified {

// System under Test

Calculator calculator = new Calculator()

// Expected behaviour

CalculatorExpected oracle = new CalculatorExpected()

// Result checker

CalculatorChecker checker = new CalculatorChecker()

add( a, b ) {

Making your own Verifying API

To let your abstraction scale to more tests and more methods to test, you separate the components into separate classes as follows.

Scenario

class CalculatorScenario {

CalculatorVerified verified = new CalculatorVerified()

testAddPositive() {

verified.add( 2, 4 )

}

testAddNegative() {

verified.add( -2, -4)

}

}

Verifying API

class CalculatorVerified {

// System under Test

Calculator calculator = new Calculator()

// Expected behaviour

CalculatorExpected oracle = new CalculatorExpected()

// Result checker

CalculatorChecker checker = new CalculatorChecker()

add( a, b ) {

actualResult = calculator.add( a, b )

expectedResult = expected.add( a, b )

checker.add( expectedResult, actualResult )

expectedResult = expected.add( a, b )

checker.add( expectedResult, actualResult )

}

}

}

Result checker

class CalculatorChecker {

add( expected, actual ) {

class CalculatorChecker {

add( expected, actual ) {

assert(expected.sum == actual.sum && expected.rounding == actual.rounding)

}

}

}

Expected behaviour

class CalculatorExpected {

class CalculatorExpected {

add( a, b ) {

total = a + b;

return[ round(total, 10), remainder(total, 10) ]

total = a + b;

return

}

}

}

Now you can see that each piece of code is separate, and can be maintained in one place. Notice that the add method signature is the same between Calculator, CalculatorVerified and CalculatorExpected! This is what makes this design so neat. You can introduce testing for subtract, divide and multiply methods in the same way.

Feedback

I realise that these topics are quite in depth, please let me know whether I am going too fast or too slow via the comments below or by email! I will respond to all feedback and take it on board.

Next time

This API only deals with simple types, e.g. int. You are testing an API that returns objects. They must be retained and passed in to other methods as per this example

Feedback

I realise that these topics are quite in depth, please let me know whether I am going too fast or too slow via the comments below or by email! I will respond to all feedback and take it on board.

Next time

This API only deals with simple types, e.g. int. You are testing an API that returns objects. They must be retained and passed in to other methods as per this example

object = system.createLocal()

id = system.persistObject(object)

saved = system.retrieveObject(id)

system.deleteObject(id)

id = system.persistObject(object)

saved = system.retrieveObject(id)

system.deleteObject(id)

My next post will solve this problem!