lundi 28 septembre 2015

Creating a thread with a Mockito mocked Runnable

I have a class that implements Runnable called DoThingInALoop. It is given to a second class that will create a thread out of it, call this thread Boss. The Boss can tell the runnable to quit and let the thread terminate. Later, it can create a new thread with that same DoThingInALoop.

When I am writing unit tests for the Boss I want to mock the DoThingInALoop because it is not the object under test. However, DoThingInALoop extends a class Loop and the code for Loop is actually being executed in the thread spawned by the Boss. That code of course runs into NullPointerExceptions because none of the member variables are set, because the object is mocked.

How can I prevent Java's Thread from "seeing through" the mock?

public class Loop implements Runnable {
    private final Object member = new Object();
    public void run() {
        // This code runs, but it shouldn't
        synchronized (member) { // Throws NPE
            ...
        }
}

public class DoThingInALoop extends Loop {
    public void stopDoingThingsInALoop() {
        // Set instance member that on next loop iteration signals thread to return
    }
}

public class Boss {
    private final DoThingsInALoop toBeMocked;
    public Boss(final DoThingsInALoop toBeMocked) {
        this.toBeMocked = toBeMocked;
    }
    public void start() {
        // Simplified
        new Thread(toBeMocked).start();
    }
    public void stop() {
        toBeMocked.stopDoingThingsInALoop();
    }
}


public class TestClass {
    @Test
    public void aTest() {
        // Setup Mocks
        DoThingsInALoop mockLoop = mock(DoThingsInALoop.class);
        Boss boss = new Boss(mockLoop);

        // Run test
        boss.start();

        // After the above line runs, a new thread is started and
        // the run() method of `Loop` executes until the NPE
        // is hit when it attempts to access a member variable
        // which is of course not set because it is a mocked object

        ...
    }
}

Aucun commentaire:

Enregistrer un commentaire