java groovy gradle spring-boot spock

java - Prueba de integración con Spring Boot y Spock



groovy gradle (4)

¿Cuál es la mejor manera de ejecutar una prueba de integración (por ejemplo, @IntegrationTest ) con Spock? Me gustaría iniciar la aplicación Spring Boot y ejecutar algunas llamadas HTTP para probar toda la funcionalidad.

Puedo hacerlo con JUnit (primero se ejecuta la aplicación y luego se ejecutan las pruebas):

@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 } }

Pero con Spock, la aplicación no se inicia:

@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 } }

Para Spock, por supuesto, he especificado las dependencias adecuadas en mi archivo de compilación Gradle:

... dependencies { testCompile ''org.spockframework:spock-core:0.7-groovy-2.0'' testCompile ''org.spockframework:spock-spring:0.7-groovy-2.0'' } ...

¿Me estoy perdiendo de algo?


Aquí hay una configuración que inicia la aplicación de arranque y luego ejecuta las pruebas de 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'' } }

Y recuerda agregar dependencias a spock y groovy dentro de build.gradle

dependencies { // other dependencies testCompile "org.codehaus.groovy:groovy-all:2.2.0" testCompile "org.spockframework:spock-core:0.7-groovy-2.0" }


El problema es que Spock Spring está buscando la anotación @ContextConfiguration de Spring y no logra encontrarla. Estrictamente hablando, MyTestSpec está anotado con @ContextConfiguration ya que es una meta-anotación en @SpringApplicationConfiguration pero Spock Spring no considera las @SpringApplicationConfiguration como parte de su búsqueda. Hay un issue para abordar esta limitación. Mientras tanto, puedes evitarlo.

Todo lo que @SpringApplicationConfiguration está haciendo es personalizar @ContextConfiguration con un cargador de contexto específico de Boot. Esto significa que puede lograr el mismo efecto utilizando en su lugar una anotación @ContextConfiguration configurada adecuadamente:

@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MyServer.class) @WebAppConfiguration @IntegrationTest class MyTestSpec extends Specification { … }

Actualización: solo para asegurarse de que está claro (y basado en los comentarios, no fue así), para que esto funcione, debe tener org.spockframework:spock-spring en classpath.


En la nueva versión de Spring Boot (1.4) en lugar de usar:

@SpringApplicationConfiguration(classes = MyServer.class) @WebAppConfiguration @IntegrationTest

Podrías usar

@SpringBootTest(classes = MyServer.class)

y podrá iniciar el contexto de la aplicación y establecer cualquier dependencia.

para obtener más información, consulte este ejemplo: http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/


Idealmente usará Spring Boot 1.4+ y Spock 1.1+.

Spring Boot agregó muchas anotaciones útiles. Además de ese @SpringBootTest que mencionó @ ignacio.suay, también agregaron @TestConfiguration que es útil si quiere usar los simulacros de Spring en sus pruebas de integración en lugar de Mockito.

Si combina @TestConfiguration con el nuevo Spock DetachedMockFactory , entonces tiene todos los componentes que necesitará para inyectar Spock Mocks en su contexto de Spring.

Tengo una publicación de blog con código de ejemplo aquí: Spring Integration Testing with Spock Mocks .

Lo rápido y sucio es esto

@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) } } }

ACTUALIZACIÓN Existe un PR para obtener más soporte nativo en Spock para inyectar Spock Mocks en el contexto de Spring para pruebas de integración. El nuevo @SpringBean y @SpringSpy serían como las anotaciones @MockBean y @SpyBean