Тест интеграции с Spring Boot и Spock
Каков наилучший способ запуска теста интеграции (например, @IntegrationTest
) со Spock? Я хотел бы загрузить загрузочное приложение Spring и выполнить некоторые HTTP-вызовы для проверки всей функциональности.
Я могу сделать это с помощью JUnit (сначала приложение запускается, а затем выполняется тестирование):
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTest {
RestTemplate template = new TestRestTemplate();
@Test
public void testDataRoutingWebSocketToHttp() {
def a = template.getForEntity("http://localhost:8080", String.class)
println a
}
}
Но с Spock приложение не запускается:
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTestSpec extends Specification {
RestTemplate template = new TestRestTemplate();
def "Do my test"() {
setup:
def a = template.getForEntity("http://localhost:8080", String.class)
expect:
println a
}
}
Для Spock, конечно, я указал правильные зависимости в файле сборки Gradle:
...
dependencies {
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'org.spockframework:spock-spring:0.7-groovy-2.0'
}
...
Я что-то пропустил?
Ответы
Ответ 1
Проблема заключается в том, что Spock Spring ищет аннотацию Spring @ContextConfiguration
и не может ее найти. Строго говоря, MyTestSpec
аннотируется с @ContextConfiguration
, поскольку это мета-аннотация на @SpringApplicationConfiguration
, но Spock Spring не рассматривает мета-аннотации как часть своего поиска. Там, чтобы устранить это ограничение, issue. Тем временем вы можете обойти это.
Все, что делает @SpringApplicationConfiguration
, это настройка @ContextConfiguration
с загрузчиком контекста загрузки. Это означает, что вы можете добиться такого же эффекта, используя вместо этого соответствующую аннотацию @ContextConfiguration
:
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTestSpec extends Specification {
…
}
Обновление: Просто чтобы убедиться, что он очищен (и на основе комментариев он не был), для этого вам нужно иметь org.spockframework:spock-spring
в пути к классам.
Ответ 2
В идеале вы будете использовать Spring Boot 1.4+ и Spock 1.1+.
Spring В Boot добавлено много полезных аннотаций. В дополнение к этому @SpringBootTest
, упомянутому в @ignacio.suay, они также добавили @TestConfiguration
, что полезно, если вы хотите использовать Spring mocks в своих интеграционных тестах вместо Mockito.
Если вы комбинируете @TestConfiguration
с новым Spock DetachedMockFactory
, тогда у вас есть все компоненты, которые вам нужно будет вставить Spock Mocks в ваш контекст Spring.
У меня есть сообщение в блоге с примером кода: Spring Тестирование интеграции с помощью Spock Mocks.
Быстро и грязно это
@SpringBootTest
class MyIntegrationTest extends Specification {
@Autowired ExternalRankingService externalRankingServiceMock
def "GetRank"() {
when:
classUnderTest.getRankFor('Bob')
then:
1 * externalRankingServiceMock.fetchRank('Bob') >> 5
}
@TestConfiguration
static class Config {
private DetachedMockFactory factory = new DetachedMockFactory()
@Bean
ExternalRankingService externalRankingService() {
factory.Mock(ExternalRankingService)
}
}
}
UPDATE
Существует PR, чтобы получить дополнительную поддержку в Spock для инъекции Spock Mocks в контекст Spring для тестирования интеграции. Новые @SpringBean
и @SpringSpy
будут похожи на аннотации @MockBean
и @SpyBean
Ответ 3
В новой Spring загрузочной версии (1.4) вместо использования:
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
Вы можете использовать
@SpringBootTest(classes = MyServer.class)
и вы сможете запустить контекст приложения и установить любую зависимость.
для получения дополнительной информации, пожалуйста, посмотрите на этот пример:
http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/
Ответ 4
Вот настройка, которая запускает загрузку, а затем запускает тесты spock:
class HelloControllerSpec extends Specification {
@Shared
@AutoCleanup
ConfigurableApplicationContext context
void setupSpec() {
Future future = Executors
.newSingleThreadExecutor().submit(
new Callable() {
@Override
public ConfigurableApplicationContext call() throws Exception {
return (ConfigurableApplicationContext) SpringApplication
.run(Application.class)
}
})
context = future.get(60, TimeUnit.SECONDS)
}
void "should return pong from /ping"() {
when:
ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080/ping", String.class)
then:
entity.statusCode == HttpStatus.OK
entity.body == 'pong'
}
}
И не забудьте добавить зависимости для spock и groovy внутри build.gradle
dependencies {
// other dependencies
testCompile "org.codehaus.groovy:groovy-all:2.2.0"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
}