У меня есть Java-приложение Swing с сетевым взаимодействием с несколькими «игроками», которые представлены как объекты-игроки, каждый со своим собственным потоком связи. В приложении есть объект «Команда», управляющий всеми объектами игроков. Несколько компонентов пользовательского интерфейса прослушивают события, передаваемые игроками через объект Team.
В моем проекте командный объект запускает все события в потоке Swing с помощью invokeLater, так что остальной части моего приложения не нужно беспокоиться о проблемах с потоками. Однако я не знаю, как протестировать класс Team в тесте JUnit.
Еще немного предыстории. Сначала у меня был объект Team, запускающий свои события в потоках объекта игрока (никакого переключения потоков). Модульный тест Team прошел успешно, но у меня возникло множество проблем с потоками в моем пользовательском интерфейсе с помощью invokeLaters и повсеместной синхронизации. Затем я решил упростить модель потоков, включив события запуска объекта Team в потоке Swing, но теперь модульный тест Team завершается ошибкой, потому что он не получает события. Что делать?
На ум приходит решение ввести дополнительный объект поверх Team, который выполняет переключение потоков и сохраняет исходный модульный тест нетронутым, но мне не нравится идея добавления сложности в производственный код только для того, чтобы модульный тест прошел успешно.




Возможно, вы можете использовать easymock, чтобы изолировать классы, которые вы хотите протестировать, и заставить макетные объекты получать события и проверять, что они запускаются.
Я бы порекомендовал EasyMock: http://www.easymock.org/
Из вашего рассказа кажется, что ваши юнит-тесты - это больше интеграционные тесты, и они очень сложные. Если это так, попробуйте упростить и изолировать. Вы, наверное, читали http://junit.sourceforge.net/doc/testinfected/testing.htm
Надеюсь, это поможет.
Когда я провел тестирование JUnit с EventQueue.invokeLater, я отделился от этой злой статики. Создать интерфейс с invokeLater можно методами isDispatchThread. Для производства реализация должна просто перенаправить на EventQueue. Для тестирования используйте свой собственный поток (который можно настраивать и отключать для каждого теста).
Еще один случайный совет:
Мне нравится твой совет, особенно второй. Ваше предложение ввести интерфейс, вероятно, будет правильным решением. Тем не менее, мне немного неудобно, что мне приходится делать это «просто», чтобы что-то проверить.
A solution that comes to mind is to introduce an extra object on top of Team that does the thread switch and keep the original unit test intact, but I do not like the idea of introducing complexity in production code just to make a unit test succeed.
Я не знаю, так ли это здесь, но я часто обнаруживаю, что добавляемая мною «сложность» на самом деле является более высоким уровнем абстракции, улучшающим код.
Первоначальная идея имитирующих объектов заключалась не в том, чтобы упростить модульное тестирование, а в «обнаружении интерфейсов», чтобы создавать интерфейсы, которые представляют абстракции на вашем вездесущем языке, а не работать на уровне API.
Я согласен со сложностью и функциональной абстракцией, но в данном случае я имею дело «только» с проблемами потоковой передачи, которые можно довольно легко решить, выполнив большинство действий в потоке пользовательского интерфейса, за исключением того, что это усложняет тестирование. Спасибо, что заставили меня переосмыслить мои абстракции!
Вы правы, что я тестирую не один класс. Что я пытаюсь достичь, так это убедиться, что взаимодействие между несколькими процессами работает на уровне команды. Это взаимодействие между объектом, который я хочу протестировать, и мне нужно подумать, чтобы найти другой способ. Спасибо за совет.