Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tomek Kaczanowski - Practical Unit Testing with JUnit and Mockito - 2013.pdf
Скачиваний:
228
Добавлен:
07.03.2016
Размер:
6.59 Mб
Скачать

Chapter 6. Things You Should Know

Listing 6.26. Testing asynchronous code - with Awaitility

Awaitility.await()

.atMost(1, SECONDS)

.with().pollInterval(100, MILLISECONDS)

.until(new Callable<Boolean>() {

@Override

public Boolean call() throws Exception { try {

verify(taskService).handle(task); return true;

} catch(AssertionError ae) { return false;

}

}

});

Personally I do not like the try-catch version of this test. It is much more complicated than the usual tests. The second version - which uses Awaitility - is more readable, but even so, it also requires us to catch a class of the Error type, which goes against the common rules of Java coding.

Spend some time learning about the Awaitility framework. You won’t use it a lot in unit tests, but it can do wonders to your test code in your integration or end-to-end tests, making it much more readable.

6.9.2. Making Asynchronous Synchronous

So far we have been concentrating on waiting for the asynchronous code. This is possible, but not without some drawbacks. Let us try a different approach now.

Let us take a look again at the code in Listing 6.22. Can you see anything which makes it asynchronous? No, there is nothing of that sort there. The asynchronous nature of this code is "injected" by a concrete implementation of the ExecutorService, which means, in turn, that if we provide a synchronous implementation of this interface, it will make our situation much simpler. At the same time, by doing this we won’t breach the contract of the ExecutorService. Even if it was designed with asynchronicity in mind, it does not demand implementations to provide such a feature.

Listing 6.27 presents such a sample implementation.

124

Chapter 6. Things You Should Know

Listing 6.27. SynchronousExecutorService

public class SynchronousExecutorService extends AbstractExecutorService { private boolean shutdown;

public void shutdown() { shutdown = true;

}

public List<Runnable> shutdownNow() { shutdown = true;

return Collections.emptyList();

}

public boolean isShutdown() { shutdown = true;

return shutdown;

}

public boolean isTerminated() { return shutdown;

}

public boolean awaitTermination(final long timeout, final TimeUnit unit) {

return true;

}

public void execute(final Runnable command) { command.run();

}

}

This implementation extends the java.util.concurrent.AbstractExecutorService class, which

allows us to implement only selected methods of the ExecutorService interface.

This is the most important part of this class: instead of executing the command in a separate thread we simply run it synchronously.

If we inject this synchronous implementation into the tested instance of the Server class, we discover that the test is now trivial. By removing the asynchronicity we have simplified this case, turning it into a normal one. There is no need for any waiting within the test code.

Listing 6.28. Testing asynchronous code - using SynchronousExecutorService

@Test

public void shouldSaveTasks() {

TaskService taskService = mock(TaskService.class);

ExecutorService executorService = new SynchronousExecutorService(); Server server = new Server(executorService, taskService);

Task task = mock(Task.class);

Collection<Task> listOfTasks = Arrays.asList(task);

server.serve(listOfTasks);

verify(taskService).handle(task);

}

6.9.3. Conclusions

In this section we have learned how to write unit tests for code which spawns new threads. We have learned two ways of doing this. The first option is to wait (preferably by constant polling) for the desired

125

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]