Unit Testing in ABS

Introduction

Similar to JUnit, ABSUnit is an ABS package, which is packaged as a Maven module. The source can be found at hats/Tools/ABS/trunk/abs-unit/m2abs-unit.

Preparing the ABS Project

To include ABSUnit, either include the .abs files in abs-unit/m2abs-unit/src/main/abs and its subdirectories, or if the project is managed using Maven, include the following in the project pom:

<dependency>
  <groupId>eu.hats-project</groupId>
  <artifactId>abs-unit</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

Writing Unit Tests

The following elements must be included in an ABSUnit project:

  • An ABS test interface which will be implemented by the ABS test class. This is annotated with [Fixture].
  • A number of test methods returning Unit in the test interface that should be called by the test driver; each one is annotated with [Test].
  • An optional datapoint method exposed by the The ABS test interface that returns a set of values as test data, annotated with [DataPoint]. If any test methods need input, it will be taken from the return value of this method.
  • An ABS test class that defines the test cases and implements the above test methods and data method. The test class is annotated with [Suite].

Test Assertions and Failures

The class ABSAssert features methods assertTrue etc. which will not terminate the program but collect test failures.

Complete example

(This example can also be found in abs-unit/m2abs-unit/src/test/abs/absunit-test.abs.)

module AbsUnit.Tests;

export AbsUnitTest, AbsUnitTestClass;

import * from AbsUnit;
import * from AbsUnit.Hamcrest;
import * from AbsUnit.Hamcrest.Core;

[Fixture]
interface AbsUnitTest { 
        [DataPoint] Set<Pair<Int,Int>> comparators();
        [Test] Unit testAssertTrue();
        [Test] Unit testAssertFalse();
        [Test] Unit testAssertEquals(Pair<Int,Int> comp);
        [Test] Unit testAssertNotEquals();
        [Test] Unit testAssertThat();
}

[Suite]
class AbsUnitTestClass implements AbsUnitTest {
        
        Set<Pair<Int,Int>> comps = EmptySet;
        ABSAssert aut;
        
        {
                aut = new ABSAssertImpl(); // AUT
                comps = set[Pair(1,1),Pair(2,2),Pair(3,3),Pair(4,4)]; //demo
        }
        
        Set<Pair<Int,Int>> comparators() {
                return comps;
        }
        
        Unit testAssertTrue() {
                aut.assertTrue(True);   
        }
        
        Unit testAssertFalse() {
                aut.assertFalse(False);
        }
        
        Unit testAssertEquals(Pair<Int,Int> comp) {
                Comparator c = new IntComparator(fst(comp),snd(comp));
                aut.assertEquals(c);
        }
        
        Unit testAssertNotEquals() {
                Comparator c1 = new IntComparator(1,2);
                Comparator c2 = new IntComparator(2,1);
                aut.assertNotEquals(c1);
                aut.assertNotEquals(c2);
        }
        
        Unit testAssertThat() {
                Comparator c = new IntComparator(1,2);
                Matcher m1 = new LessThan(c);
                Matcher m2 = new MoreThan(c);
                Matcher m3 = new Is(c);
                
                Matcher tt = new TrueMatcher();
                Matcher ff = new FalseMatcher();
                Set<Formula> fs = set[fm(ff),fm(ff),fm(tt),fm(ff),fm(ff)];
                
                Formula f = And(And(fm(m1),Not(Or(fm(m2),fm(m3)))),AnyOf(fs));
                Matcher corem = new CoreMatcher(f);
                
                aut.assertThat(corem);
        }
        
}

class TrueMatcher implements Matcher {
        Bool matches() {
                return True;
        }
}

class FalseMatcher implements Matcher {
        Bool matches() {
                return False;
        }
}

class IntComparator(Int expected, Int actual) implements Comparator {
        Int compare() {         
                return expected - actual;       
        }
}

Running Tests

Run maven goal javatest (to execute tests in the java backend) or maudetest (to execute tests in the maude backend). An example of this can be found in abs-unit/m2abs-unit/pom.xml.

Alternatively, bash script frontend/src/bash/generateTestRunner can be used:

generateTestRunner -o <path-to-your-runner-file> <abs-files> 

(e.g. currently at m2abs-unit/src/test/abs then execute generateTestRunner -o runner.abs *.abs ../../../src/main/abs/*.abs)

This command creates a module AbsUnit.TestRunner containing a main block that executes concurrently all tests with [TestClass] annotated.

generateMaude/Java -main=AbsUnit.TestRunner ... 

(e.g. currently at m2abs-unitsrc/test/abs then execute generateMaude -main=AbsUnit.TestRunner *.abs ../../../src/main/abs/*.abs)

This command generates the tests into corresponding backends pointing to the main block at AbsUnit.TestRunner as the initialisation code.