web-dev-qa-db-ja.com

Spring BootおよびSpockとの統合テスト

統合テストを実行する最良の方法は何ですか(例: @IntegrationTest )Spockで? bootstrap= Spring Bootアプリケーション全体を実行し、いくつかの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'
}
...

何か不足していますか?

36
kuceram

問題は、Spock SpringがSpringの@ContextConfigurationアノテーションを探していて、それを見つけられないことです。厳密に言えばMyTestSpecis@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クラスパス。

49
Andy Wilkinson

Spring Boot 1.4+およびSpock 1.1+を使用するのが理想的です。

Spring Bootは多くの便利な注釈を追加しました。それに加えて @SpringBootTest @ ignacio.suayが言及したこと、彼らは@TestConfigurationこれは、統合テストでMockitoの代わりにSpringモックを使用する場合に便利です。

@TestConfiguration新しいSpock DetachedMockFactoryを使用すると、Spock Mocksを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 [〜#〜]Spockを注入するためにSpockでよりネイティブなサポートを得るために a PR があります統合テストのためにSpringコンテキストをモックします。新しい @SpringBeanおよび@SpringSpy@MockBeanおよび@SpyBean注釈

[〜#〜] update [〜#〜]Spock 1.2にはこれらの変更が含まれるようになりました。ドキュメントが更新されるまで、ここに Spring統合テスト用Spock 1.2アノテーションのプレビュー があります。

8
Snekse

新しいSpring Bootバージョン(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/

3
ignacio.suay

ブートアプリケーションを起動してから、スポックテストを実行するセットアップを次に示します。

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

そして、build.gradle内のspockとgroovyに依存関係を追加することを忘れないでください

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