web-dev-qa-db-fra.com

Test d'intégration avec Spring Boot et Spock

Quelle est la meilleure façon d'exécuter un test d'intégration (par exemple, @IntegrationTest ) avec Spock? Je voudrais bootstrap toute l'application Spring Boot et exécuter quelques appels HTTP pour tester toute la fonctionnalité.

Je peux le faire avec JUnit (d'abord l'application s'exécute, puis les tests s'exécutent):

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

Mais avec Spock, l'application ne démarre pas:

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

Pour Spock, bien sûr, j'ai spécifié les dépendances appropriées dans mon fichier de construction Gradle:

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

Suis-je en train de manquer quelque chose?

36
kuceram

Le problème est que Spock Spring recherche _ @ContextConfiguration annotation et n'arrive pas à la trouver. À proprement parler MyTestSpec est annoté avec @ContextConfiguration car c'est une méta-annotation sur @SpringApplicationConfiguration mais Spock Spring ne considère pas les méta-annotations comme faisant partie de sa recherche. Il y a un problème pour résoudre cette limitation. En attendant, vous pouvez contourner ce problème.

Tout ça @SpringApplicationConfiguration est en train de personnaliser @ContextConfiguration avec un chargeur de contexte spécifique au démarrage. Cela signifie que vous pouvez obtenir le même effet en utilisant un _ correctement configuré @ContextConfiguration annotation à la place:

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

Mise à jour: Juste pour être sûr que c'est clair (et sur la base des commentaires, ce n'était pas le cas), pour que cela fonctionne, vous devez avoir org.spockframework:spock-spring sur le chemin de classe.

49
Andy Wilkinson

Idéalement, vous utiliserez Spring Boot 1.4+ et Spock 1.1+.

Spring Boot a ajouté de nombreuses annotations utiles. En plus de ça @SpringBootTest que @ ignacio.suay a mentionné, ils ont également ajouté @TestConfiguration ce qui est utile si vous souhaitez utiliser Spring Mocks dans vos tests d'intégration au lieu de Mockito.

Si vous combinez @TestConfiguration avec le nouveau Spock DetachedMockFactory, vous disposez alors de tous les composants dont vous aurez besoin pour injecter Spock Mocks dans votre contexte Spring.

J'ai un article de blog avec un exemple de code ici: Spring Integration Testing with Spock Mocks .

Le rapide et sale est-ce

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

[~ # ~] mise à jour [~ # ~] Il y a n PR pour obtenir plus de support natif dans Spock pour l'injection de Spock Se moque dans le contexte Spring pour les tests d'intégration. Le nouveau @SpringBean et @SpringSpy serait comme le @MockBean et @SpyBean annotations

[~ # ~] mise à jour [~ # ~] Spock 1.2 devrait maintenant inclure ces changements. Jusqu'à la mise à jour de la documentation, voici un aperçu des annotations Spock 1.2 pour les tests d'intégration de Spring .

8
Snekse

Dans la nouvelle version Spring Boot (1.4) au lieu d'utiliser:

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

Vous pourriez utiliser

@SpringBootTest(classes = MyServer.class)

et vous pourrez démarrer le contexte de l'application et définir n'importe quelle dépendance.

pour plus d'informations, veuillez consulter cet exemple: http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/

3
ignacio.suay

Voici une configuration qui démarre l'application de démarrage puis exécute des tests 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'
}
}

Et n'oubliez pas d'ajouter des dépendances à spock et groovy à l'intérieur build.gradle

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