Юнит-тесты SpringBoot с несколькими TomcatServletContainerInitializer — BindException: адрес уже используется»

У меня есть приложение весенней загрузки, и в настоящее время все мои тесты работают зеленым, если я запускаю их отдельно, то есть вручную, но когда я запускаю команду пакета maven, все тесты запускаются в последовательном режиме, то есть друг за другом. Что происходит тогда, так это то, что я получаю:

"java.net.BindException: Address already in use".

По сути, поскольку тест выполняется последовательно, все они пытаются получить сокет 127.0.0.1:8081. А поскольку сокет находится в состоянии TIME_WAIT, второй тест не может затребовать этот сокет. то есть вывод netstat -apn

netstat -apn |grep -i 8080

tcp   0      0 127.0.0.1:8080          127.0.0.1:33952         TIME_WAIT 
  • #P4# <блочная цитата> #P5# #P6#

То, что мне сейчас нужно, — это функция, позволяющая указать, какой клиент TomcatServletContainerInitializer я могу запустить, т. Е. У меня будет 5 разных, все они прослушивают разные порты / сокеты. Проблема в том, что если у меня есть 5 разных классов конфигурации TomcatEmbeded, которые все отмечены «@Profile («Разработка»)», то как я могу сказать junit выполнить тот, который мне нужен. Я устал использовать @SpringApplicationConfiguration , но это не работает.

@SpringApplicationConfiguration(classes = {
        ...
        TomcatEmbededDevelopmentTesting1Profile.class,
        ...
        } )

затем я нашел в сети статью, в которой объясняется, что есть какая-то волшебная аннотация @IntegrationTest("server.port:0"), которая предположительно рандомизирует этот порт, но у меня это тоже не сработало. Как правильно поступить весной? Любые подсказки приветствуются.

вот пример моего теста:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(listeners={ ServletTestExecutionListener.class,
                                    DependencyInjectionTestExecutionListener.class,
                                    DirtiesContextTestExecutionListener.class,
                                    WithSecurityContextTestExecutionListener.class 
                                    }
        )

@SpringApplicationConfiguration(classes = {
        SecurityWebApplicationInitializerDevelopment.class, 
        SecurityConfigDevelopment.class, 
        TomcatEmbededDevelopmentTesting1Profile.class,
        Internationalization.class, 
        MVCConfigDevelopment.class,
        PersistenceConfigDevelopment.class,
        ServerAuthenticationSuccessHandler.class,
        ServerRedirectAuthenticationSuccessHandler.class,
        LogicServiceRegistryPostProcessor.class
        } )
@WebAppConfiguration
@EnableWebSecurity
@EnableWebSocket
@EnableGlobalMethodSecurity(prePostEnabled = true)
//@IntegrationTest({"server.port=0", "management.port=0"})
@ActiveProfiles("Development")
    public class quickTest extends TestCase {
..
}

person Tito    schedule 14.06.2016    source источник
comment
Какую версию Spring Boot вы используете?   -  person Sam Brannen    schedule 15.06.2016
comment
Откуда TestCase? Если это из JUnit 3.8, то вам следует немедленно удалить extends TestCase, так как вы фактически используете JUnit 4.x.   -  person Sam Brannen    schedule 15.06.2016
comment
@SamBrannen Сэм, я использую артефакт spring/boot-starter-parent версии 1.3.5.RELEASE. После вашего комментария я удалил директиву extends TestCase, однако я все еще получаю это исключение привязки, т.е. адрес уже используется. У вас есть другая идея, что я могу попытаться изменить?   -  person Tito    schedule 23.06.2016
comment
относительно того, что еще попробовать, вы видели мой ответ?   -  person Sam Brannen    schedule 10.09.2016


Ответы (1)


Во-первых, аннотации @Enable* не поддерживаются в тестовых классах с Spring Boot 1.3.x. Поэтому удалите их и переместите в настоящие @Configuration классы.

Во-вторых, предоставление огромного списка классов для @SpringApplicationConfiguration — худшая практика. Лучше всего определить один класс @Configuration для ваших интеграционных тестов, который использует @Import для включения любых других классов конфигурации, которые вам нужны.

В-третьих, используйте @WebIntegrationTest(randomPort = true) вместо @WebAppConfiguration.

В-четвертых, не расширяйте TestCase: это JUnit 4, а не JUnit 3.

В-пятых, не включайте ServletTestExecutionListener: он используется только для интеграционного тестирования вне контейнера, а вы выполняете интеграционное тестирование внутри контейнера (т. е. во встроенном контейнере Tomcat Servlet).

В-шестых, если вам нужен случайный номер порта, просто введите его через @Value("${local.server.port}").

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(
    listeners = WithSecurityContextTestExecutionListener.class,
    mergeMode = MERGE_WITH_DEFAULTS
)
@SpringApplicationConfiguration({
        SecurityWebApplicationInitializerDevelopment.class, 
        SecurityConfigDevelopment.class, 
        TomcatEmbededDevelopmentTesting1Profile.class,
        Internationalization.class, 
        MVCConfigDevelopment.class,
        PersistenceConfigDevelopment.class,
        ServerAuthenticationSuccessHandler.class,
        ServerRedirectAuthenticationSuccessHandler.class,
        LogicServiceRegistryPostProcessor.class
        })
@WebIntegrationTest(randomPort = true)
@ActiveProfiles("Development")
public class QuickTest {

    @Value("${local.server.port}")
    int port;

    // ...
}

Итак, посмотрите, поможет ли это вам в дальнейшем, и прочитайте Справочное руководство по Spring Boot для получения дополнительной информации о поддержке тестирования Spring Boot.

person Sam Brannen    schedule 23.06.2016