1. Reading

  • Horstmann Core Java, Ed 11, Vol II, Ch 2.2

  • Horstmann Core Java, Ed 11, Vol II, Ch 4

2. Testing

2.1. Test and Threads

Sometime you have to test the cooperation of two 'programs'.

In week 9 you will be programming a simple file transport protocol using a client and a server. To test the cooperation, you need to have the server running while using the client. For that, you can use the fact that server and client can run in the same JVM, but on different threads.

To do that in a test class you could do start the server before all tests in a test class are execute. For good measure, shut the server down after all tests have executed.

The examples below are from the sebiftp exercise in week 9.

start server used by all tests
static SebiFtpServer server;

@BeforeAll

public static void startServer() throws IOException {

    server = new SebiFtpServer( new String[]{Integer.toString(16016)} );
    new Thread( () -> {
        try {
            server.start();
        } catch ( IOException ex ) {
            Logger.getLogger( TransferTest.class.getName() ).log( Level.SEVERE, null, ex );
        }

    } ).start();
}
test both via the client
// some test code here
SebiFtpClient.main( new String[]{ absolutePath, localFile } );
// some asserts here.
shut the server down
@AfterAll
static void stopServer() throws IOException{
    server.stop();
}

2.2. Custom Test Data Class.

There are cases where a csv file does not cut it and the test data need some massaging before being able to use them.

In such cases rolling your own data class can be helpfull.

First you design a data class, that provides the data you need in a test, then create static instances of the data, and provide a stream stream of them.

The example is from the templating engine in week 9.

test data class ET
static class ET {

    final String prefixSigil;
    final String postfixSigil;
    final String in;
    final String expected;
    final Map<String, String> map = new HashMap<>(); (1)
    ET( String presig, String postSig, String s1, String s2, String... kv ) {
        this.prefixSigil = presig;
        this.postfixSigil = postSig;
        in = s1;
        expected = s2;
        for ( int i = 0; i < kv.length; i += 2 ) {
            map.put( kv[ i ], kv[ i + 1 ] );
        }
    }
}

static ET et( String presig, String postSig, String s1, String s2, String... kv ) { (2)
    return new ET( presig, postSig, s1, s2, kv );
}
1 The test data provide a map.
2 Helper method to ease the definition on the test data values.
test data instances (abbreviated) as a stream
static Stream<ET> getTestValues() { (1)
    // we use a helper class ET to collect strings into a engine test data object.
    ET[] testData = new ET[]{
        et( "{{","}}", "hello {{world}}...", "hello Schöne Heimat...",
        "world", "Schöne Heimat" ),
        et( "{{","}}", "hello {{süßes}}", "hello Schöne Heimat", "süßes", "Schöne Heimat" )
    };
    return Arrays.stream(testData);
}
1 Name of the stream providing method is getTestValues
test method declaration
@ParameterizedTest
@MethodSource( "getTestValues" ) (1)
public void testEngine( ET et ) {
  // remainder left out
}
1 The method name in this snippet is the one declared in the previous code snippet.

The way you combine test data generation is up to you, you could for instance have a stream generating method read the data from a file, converting them to objects in a way similar as in the csv to object approach and provide the stream to the test framework in a way similar to the above. See the example below.

example test data from file using CSVObjectStream.
Stream<Truck> getTestValues(){
  return new CSVObjectStream( Truck.class, Paths.get( "trucks.csv" ) )
  .stream(Truck::new, x -> ! x[o].startsWith("#"));
}

2.3. Squeezing the last coverage out

The example code below is given as an illustration to squeeze the last bit of coverage out of your code in case your code catches exceptions that never occur in a normal situation, but you have to deal with them anyway, because the exceptions are checked exceptions, and you do not have the option to pass them on in a throws clause, because some code up in the call stack does not accept that. We ran into this situation while developing the templating engine.

In normal production code squeezing the last drop of coverage out of your test code is rarely worth the effort. In cases where you project manager or architect insists on high coverage, here is how to deal with such request. Do not make a habit out of it, because it adds little business value.

You have some code that uses a resource-method that throws an exception. The way to go about to cover the catch block too is to mock the resource for that test case and let the mock throw the to be caught exception.

to cover code
   void flush( char c ) {
        if ( c == '\0' ) {
            return;
        }
        try {
            out.append( c );
        } catch ( IOException ex ) { (1)
            Logger.getLogger( Engine.class.getName() ).log( Level.SEVERE, null,
                    ex );
        }
    }
1 In normal cases this catch block is not reached.
test that covers the catch block
    @Test
    public void flush() throws IOException {
        Appendable out = mock( Appendable.class );  (1)
        Logger engineLogger = Logger.getLogger( Engine.class.getName() ); (2)
        Handler handler = mock( Handler.class );
        engineLogger.addHandler( handler ); (3)
        Mockito.doThrow( new IOException( "test" ) ).when( out ).append( 'o' ); (4)

        Engine engine = new Engine( Map.of() ).readingString( "Hello world" ).writing( out );
        engine.run(); (5)

        verify( handler, atLeast( 1 ) ).publish( any() ); (6)
    }
1 Mock the output resource that should throw the exception
2 Get the a logger and
3 give it a mock handler as proof that a logging statement on the logger occurred.
4 Make the output mock throw an exception on a typical output, the character 'o' in this test.
5 Run the SUT
6 Make it a real test by ensuring that logging occurred. Since the publish method is the abstract method to implement, that is the candidate method to verify in a custom handler.

The code above is from the template engine, an exercise in week 9. Using a few variants of this code covers it all.

3. Slides:

4. Additional pointers

Decorator pattern explanation: here

5. Week 9 exercises

Template Engine

Template Engine

Use case: Think serial mail or mail merge or something similar.

The code is also a kind of template, you need to fill in the empty spots, like in an assessment.

sigil symbols There will be talk about sigil, a magic sign. In the example we use two:
'{{' as starter and '}}' as terminator, but the solution is flexible enough to take any other pair you like. Sigil stands for the character or character-sequence given and is there to make parsing of template text easier. By choosing a proper set, they will not handicap what you can write in your template text. The defaults are quite reasonable. And if you do, you can always escape.

Use case and idea
This exercise is about a simple templating engine.

Its usecase is a typical serial letter generator. This comes in handy when you want to send 'personalised' emails to students. A seasoned informatics person knows you should not use eval(…​) for that, because that will potentially execute any code.

Say you have some text and you want to substitute certain words with something from a data source, such as student names and/or grades. Then you could embellish the text with special tokens called sigils (magic signs) that help to find the words to be substituted. An example may help:

Dear {{teacher}},

We would like to complain about the module {{mod}}.
We learn to little and the examples are way to trivial.
We would like to receive our moneys worth of teaching.
Kind regards,
The students.

In the example the magic signs are the {{ and }} sequences, anything in between is understood as key in the map, and when found, replaced by the mapped value.

If the map is filled like:
Map<Object, String> map = Map.of(
        "teacher", "Richard van den Ham",
        "mod", "Programming Concepts 2 (PRC2)"
);
Then the engine can be created and started as
Function<String, String> lookup = ( s ) -> map.getOrDefault( s, "" );
// write to file.
new Engine( "{{", "}}", lookup )
        .reading( "letter.txt" )
        .writing( "mail-out.txt" )
        .run();

This program will print to a the file name 'mail-out.txt'.

sample output
Dear Richard van den Ham,

We would like to complain about the module Programming Concepts 2 (PRC2).
We learn too little and the examples are way to trivial.
Kind regards,
The students.

Design

The design is about a simple state machine with five states. See figure state diagram.

In addition the "templating engine" has two helper classes, a SigilMatcher and the enum TemplateState. See the class diagram in the class diagram. These classes are package private and so are the methods in them.

The methods you use to configure the engine, constructors, the readingXXX(…​), and writing(…​) are part of a so called fluent api. They, plus the accept(int) and run() methods are the only methods that are part of the public API.

Given the sigils as above, the Test data in the EngineTest test class are:

test data
static Stream<ET> getTestValues() {
    // we use a helper class ET to collect strings into a engine test data object.
    ET[] testData = new ET[]{
                et( "{{", "}}", '\\', "hello {{world}}...", "hello Schöne Heimat...",
                "world", "Schöne Heimat" ),
                et( "{{", "}}", '\\', "hello {{süßes}}", "hello Schöne Heimat", "süßes", "Schöne Heimat" ),
                et( "{{", "}}", '\\', "now somethings with {{two}} words to {{replace}}", // template
                "now somethings with more words to work with", // expected
                "two", "more", //  kv 1
                "replace", "work with" // kv 2
                ),
                et( "{{", "}}", '\\', "Niks geen substituties", "Niks geen substituties" ),
                et( "{{", "}}", '\\', "Leave me {alone}}", "Leave me {alone}}" ), // incomplete starter
                et( "{{", "}}", '\\', "Leave me { {alone}}", "Leave me { {alone}}" ), // broken starter
                et( "{{", "}}", '\\', "Leave me {{alone}, go away", "Leave me {{alone}, go away" ), // broken postfix
                et( "{{", "}}", '\\', "Leave me {{alone}}, go away I am Broken at the {{Tail}",
                "Leave me , go away I am Broken at the {{Tail}" ), // broken postfix at tail
                // text below for escaping version only.
                // Note the duplication of the \ char to make the strings valid Java strings.
                et( "{{", "}}", '\\', "Look ma, this is how you write a sigil"
                + " text in your letter: \\{{my dear boy}}"
                + " and I used \\\\ to write this example",
                "Look ma, this is how you write a sigil"
                + " text in your letter: {{my dear boy}}"
                + " and I used \\ to write this example",
                "not used", "not used either" // kv1
                ),
                // below different sigil lengths, 1 and 3.
                et( "{", "}", '\\', "hello single char template {world}...", "hello single char template Schöne Heimat...",
                "world", "Schöne Heimat" ),
                et( "{{{", "}}}", '@',
                "And it works with three and other escape as well."
                + "text in your letter: {{{my dear boy}}}.",
                "And it works with three and other escape as well."
                + "text in your letter: well, that depends.",
                "my dear boy", "well, that depends" ), // kv1
            };
    return Arrays.stream( testData );
}

Your Task.

The sigil matcher is complete, tested and implemented. It is also a state full class, however NOT using the state pattern, but simply counting the characters matched. So that implementation will provide little help in your real task. Sorry.

  1. Implement this design. Develop test driven. (Should be easy. The test data are already waiting in the code). You only need to complete the one and only test method in the class. Use Hamcrest assertThat.

  2. You can start your test at the very top, the engine.

  3. Once you have the first version ready, modify the design to add an escape facility by adding (and implementing a state, TDD style), allowing to add the sigil to the template text by escaping it. Use the backslash as escape token and remember to escape that too. (It is simpler than you think).

  4. Add an escape facility so that you can write a letter showing off the possibilities of this simple tool.
    Hint Add a state.

Hints
A statemachine reacts to 'events' or method calls.

  • The functions in java.util.function have no member that processes chars. The reason for that is that in many case chars can be processed as ints. Also, when retrieving the character elements from a CharSequence (an interface implemented by the java.lang.String class) using either the method IntStream chars() or IntStream codePoints() will produce an intStream. For the processing part that is just fine. One needs only to remember to cast the values to `char`s when writing them to the output.

  • In this state machine the event of importance is the invocation of the method Engine.accept(int char), which is stipulated by the IntConsumer functional interface.

  • The Engine provides an accept(int) method that matches the IntConsumer functional interface. This means that is the engine is fed one character at the time. You can use that method as a method reference (this::accept) or a lambda expression. ((c) → accept(c)).

  • To use a file with text as input template you will have to turn that file into many accept calls.

    • Think of streams, and use the method Files.lines(), study what flatMap and flatMapToInt is all about and use it to get the result: from stream of strings to stream of int, one int per character of the string. In the String API you have two options. Either one will do in most cases.

  • Make a drawing (pencil, paper). Files.line produces a stream, the Engine puts itself at the end, consuming the stream of `int`s. You have to tie these parts together.

engineclassesx
Figure 1. class diagram

In the class diagram of engine Substitute Engine for the T in the ObjIntConsumer<T>.
Remember that an ObjIntConsumer takes two inputs and produces no direct return value. State Pattern in action with a twist of enum thrown in.

templaterStateMachinex i
Figure 2. state diagram

There is a difference between the state machine diagram on this website and in the source folder in the project. The diagram on this website should take precedence, because this is how we test it now. The difference actually only affects the way wrongly formatted template documents are handled, so the choice is arbitrary. In the design in this website, the 'junk' is output, in the other it is discarded. Showing the junk may help the user to find the error in the template earlier. A more professional variant might produce some diagnostics, but we left that out of the exercise.

5.1. Test run reports Week 9