Skip to content

Implement your own Shark ASAP application (4 of 5)

Thomas Schwotzer edited this page Jan 4, 2022 · 16 revisions

Step 4: Implement and test

There are German video explaining a) testing with ASAP and b) adding your code to an Android app.

Software must be tested. Full stop. No exceptions. Fortunately, we can follow / copy / adopt existing tests. We assume, you implement a SharkComponent. Good choice! Have a look into our test case in project SharkPeer. That test case is explained in more detail in this section.

Setup your Shark component

Setting up your component is not our business, though. There is a only a sketch of a real component in our tests case. That is the setupComponent() method:

private YourComponent setupComponent(SharkPeer sharkPeer) throws SharkException {
    // give peer anything that is needed to create your component
    sharkPeer.addComponent(new YourComponentFactory(), YourComponent.class);
    // force peer to create your component
    YourComponent yourComponent = (YourComponent) sharkPeer.getComponent(YourComponent.class);
    // return the object reference of your component
    return yourComponent;
}

A SharkPeer object is before setting up your component. This object comes as parameter. Remaining lines are already explained in a previous section. You add your component to the peer by creating a factory object. You can now force the peer to create an object of your component. This method simply returns this object reference.

Pretty simple. No hidden tricks.

Setup a Shark peer

Have a look at our sendAMessage() test case.

    ////////////// setup Alice
    SharkTestPeerFS.removeFolder(ALICE_ROOTFOLDER);
    // setup a shark peer with a unique id and folder
    SharkTestPeerFS aliceSharkPeer = new SharkTestPeerFS(ALICE, ALICE_ROOTFOLDER);

We remove a folder first. That's helpful in automated tests. That is no good idea in a real application. You would remove anything that was kept by our peer. Any message, any setting and memory of eras would be gone. Good for tests.

We create a SharkPeer in the second line. Actually, we create an instance of SharkTestPeerFS which is a subclass of SharkPeerFS. This test class adds just a few methods which come in handy for automated tests. All other Shark and ASAP related methods are derived from the real SharkPeer implementation. That is not a variant of mocking. You actually test your application with the real SharkPeer implementation.

Rule: Use SharkTestPeerFS instances in your tests. Use instances of SharkPeerFS in your application.

Setup your test

We have got a shark peer object. We can initialize your component now. Most applications need a listener. We produce one and add it as listener. You should do the same with your listener. Finally, we start our peer.

    // setup your component with our shark peer.
    YourComponent aliceComponent = this.setupComponent(aliceSharkPeer);
    // create and your listener
    ExampleYourComponentListener aliceListener = new ExampleYourComponentListener();
    aliceComponent.subscribeYourComponentListener(aliceListener);
    // start our shark peer
    aliceSharkPeer.start();

We need to peers in our test example. We create another one, called Bob. Same steps with a different peer.

    ////////////// setup Bob
    SharkTestPeerFS.removeFolder(BOB_ROOTFOLDER);
    SharkTestPeerFS bobSharkPeer = new SharkTestPeerFS(BOB, BOB_ROOTFOLDER);
    YourComponent bobComponent = this.setupComponent(bobSharkPeer);
    ExampleYourComponentListener bobListener = new ExampleYourComponentListener();
    bobComponent.subscribeYourComponentListener(bobListener);

    // Start bob peer
    bobSharkPeer.start();

Now, we have to running peers in our tests case. Note again: That is not a mock. We launched the real SharkPeer implementation. You can create as many peers as you like. We only need two in this example.

Run your test

Peers are up and running. Let's do something.

bobComponent.sendBroadcastMessage(YOUR_URI, "Hi all listeners of A");

That is not very exciting. Component Bob sends a message. More specific, we call a method on your API. We ask the component to send a message. We know what happens. We delegate this task to our peer. It will deliver this message to any encountered peer. This is just an example.

You will call another method with different parameters on your API in your tests.

Note: Methods should be called after starting your peers.

There is no communication yet. Peers have not met. In ASAP-terms: There was no ASAP encounter yet. Now, we use a special feature of our test peer implementations.

aliceSharkPeer.getASAPTestPeerFS().startEncounter(7777, bobSharkPeer.getASAPTestPeerFS());

Each Shark peer contains an ASAP peer. We get a reference of the test sub class and call the startEncounter() method.

This method is added by our ASAP and Shark peer test classes. It creates a TCP connection (on port 7777 in this case) and launches an ASAP encounter with both peers.

Again: That is not a mock. We create a real TCP connection and let both Shark peer run a real ASAP encounter.

Test your application logic

That’s it. It is your turn now. You have to test if something useful happened. In our case, we test if our the Alice component has received a message from Bob.

// give them moment to exchange data
Thread.sleep(200);
//Thread.sleep(Long.MAX_VALUE);
System.out.println("slept a moment");

// exactly one message should be received by Alice
Assert.assertEquals(1, aliceListener.counter);

Automated tests are tricky in some aspects. Race conditions is one of those aspects. Peers launch their own threads to exchange data during an encounter. Automated tests are a multi-threaded system. We need the test thread to rest for a moment to give other threads a chance to do something. We let this thread sleep a moment (200 milliseconds in this case).

You will most probably debug you application with your preferred IDE. Debugging will take more than just a few (milli-) seconds. You might need to let the test thread sleep much longer when you debug your application. That is what we do: Thread.sleep(Long.MAX_VALUE):

Finally, we test if a single message was received my Alice. You have do implement your own code to test of a successful encounter.

Write as much tests as you can imagine. Start implementing a GUI once you find your application stable enough. Come back to this step if you find further bugs. You will most probably. Implement another test. Fix the bug. Bug fixing is much easier with automated tests than by clicking on a e.g graphical user interface.

Clone this wiki locally