Как тестировать многопоточный код с Junit?

322
28 марта 2017, 11:40

У меня код, который нужно протестировать на потокобезопасность, я хочу сделать это при помощи junit, подскажите как это делается?

Вот код:

public class UserStorage implements Storage {
    private final Map<Integer, Account> accounts;
    private final Object monitor;
    UserStorage() {
        this.accounts = new HashMap<>();
        this.monitor = new Object();
    }
    @Override
    public boolean addAccount(final Account account) {
        synchronized (this.monitor) {
            final Account a = this.accounts.get(account.getId());
            if (a != null) {
                return false;
            }
            this.accounts.put(account.getId(), account);
            return true;
        }
    }
}

Если тестировать этот метод, не в контексте многопоточности, то получается так:

@Test
public void whenAddNewAccountThenMethodNewAccountReturnTrue() {
    Account account = new User(new BigDecimal("1"), "name", 1);
    Storage storage = new UserStorage();
    boolean result = storage.addAccount(account);
    assertTrue(result);
}
@Test
public void whenAddNewAccountButAccountIdIsExistThenMethodAddAccountReturnTrue() {
    Account account = new User(new BigDecimal("1"), "name", 1);
    Storage storage = new UserStorage();
    storage.addAccount(account);
    boolean result = storage.addAccount(account);
    assertFalse(result);
}

И так далее...

Но, у меня задание в том, что-бы код был потокобезопасный, соответственно, я должен как-то, и протестировать его на это. Помогите пожалуйста, подскажите направление.

Answer 1

Поскольку вызывать ассерты не в потоке junit нельзя, то вы можете запустить тестовые треды через Executors а потом, например, создав барьер дождаться выполнения их всех и проверить уже что получилось.

P.S> Если у вас запись будет редкая, а чтение часто, то не используйте synchronized. Лучше всего StampedLock или если не Java 8, то ReadWriteLock.

Пример:

CompletableFuture future1 = CompletableFuture.runAsync(() -> { 
    // Выполняем что-то с тестируемым объектом в одном потоке 
}); 
CompletableFuture future2 = CompletableFuture.runAsync(() -> { 
    //Выполняем что-то с тестируемым объектом в одном потоке 
}); 
СompletableFuture.allOf(future1, future2).thenAccept(v -> { 
    //Делаем проверки 
}).get()
READ ALSO
Сборка Maven проекта

Сборка Maven проекта

Проект разбит на 3 модуля:

225
Правильная архитектура сервлета Java

Правильная архитектура сервлета Java

Архитектура сервлета: слой view(jsp) обращается к классу расширяющему HttpServlet

285
Java взаимодействие с USB

Java взаимодействие с USB

Есть приложение написанное на JAVA в intellij IDEA под Windows 64Необходимо сделать usb ключ

272
SQLite как сортировать данные?

SQLite как сортировать данные?

Здравствуйте! Суть вопроса такова, делаю простенький quiz game, у пользователя есть выбор категорийНе могу понять как сортировать вопросы в базе...

282