web-dev-qa-db-ja.com

RestTemplateを使用したRESTfulサービスのテスト

私のアプリケーションには、多くのRESTサービスがあります。すべてのサービスのテストを作成しました:

org.springframework.web.client.RestTemplate

REST-Serviceの呼び出し(例:次のようになります。

final String loginResponse = restTemplate.exchange("http://localhost:8080/api/v1/xy", HttpMethod.POST, httpEntity, String.class)
        .getBody();

その後、応答本文を確認します-すべて正常に動作します。欠点は、REST-Servicesを呼び出すためにアプリケーションを確実に起動する必要があることです。

私の質問は、JUnit- @Testメソッドでこれをどのように行うことができるのでしょうか?これは、Spring Bootアプリケーションです(Tomcatが組み込まれています)。

手伝ってくれてありがとう!

12
quma

ドキュメントにはこれに関する良い chapter があります。何ができるかを完全に理解するためにそれを一読することをお勧めします。

サーバー全体を起動し、完全なシステムをテストできるので、カスタム構成で@IntegrationTestを使用するのが好きです。システムの特定の部分をモックで置き換えたい場合は、特定の構成またはBeanを除外し、独自の構成またはBeanで置き換えることでそれを行うことができます。

以下に小さな例を示します。 MessageServiceインターフェースから除外したのは、IndexControllerから明らかなことであり、デフォルトの実装-DefaultMessageService-は関係ないためです。

それは、アプリケーション全体からDefaultMessageServiceを除いてスピンアップしますが、代わりに独自のMessageServiceを使用します。次に、RestTemplateを使用して、テストケースで実行中のアプリケーションに実際のHTTP要求を発行します。

アプリケーションクラス:

IntegrationTestDemo.Java:

@SpringBootApplication
public class IntegrationTestDemo {

    public static void main(String[] args) {
        SpringApplication.run(IntegrationTestDemo.class, args);
    }

}

IndexController.Java:

@RestController
public class IndexController {

    @Autowired
    MessageService messageService;

    @RequestMapping("/")
    String getMessage() {
        return messageService.getMessage();
    }
}

テストクラス:

IntegrationTestDemoTest.Java:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfig.class)
@WebIntegrationTest // This will start the server on a random port
public class IntegrationTestDemoTest {

    // This will hold the port number the server was started on
    @Value("${local.server.port}")
    int port;

    final RestTemplate template = new RestTemplate();

    @Test
    public void testGetMessage() {
        String message = template.getForObject("http://localhost:" + port + "/", String.class);

        Assert.assertEquals("This is a test message", message);
    }
}

TestConfig.Java:

@SpringBootApplication
@ComponentScan(
    excludeFilters = {
        // Exclude the default message service
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = DefaultMessageService.class),
        // Exclude the default boot application or it's
        // @ComponentScan will pull in the default message service
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = IntegrationTestDemo.class)
    }
)
public class TestConfig {

    @Bean
    // Define our own test message service
    MessageService mockMessageService() {
        return new MessageService() {
            @Override
            public String getMessage() {
                return "This is a test message";
            }
        };
    }
}
17
Raniz

エンドツーエンド(統合)テストを探していなかった場合は、MockRestServiceServerが役立ちます。テストケースを実際のサービスから切り離すことは非常に便利だとわかりました。

春のドキュメントは言った:

RestTemplateの直接または間接的な使用を伴うテストに使用されます。 RestTemplateを介して実行される予想されるリクエストと、そのために返信するためのモック応答をセットアップする方法を提供します実際のサーバーの必要性を取り除く

公式ドキュメント


もう1つのヒントは、requestToを自動的にインポートできないことです。

server.expect(manyTimes(), requestTo("/hotels/42")) ....

org.springframework.test.web.client.match.MockRestRequestMatchersの静的メソッドです

9
simomo

RESTにSpring MVCを使用しているため、MockMVC()をインスタンス化して提供されるテスト機能を使用することをお勧めします。次のようなテストを有効にします。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
 ... // any required Spring config
)
@WebAppConfiguration
public class RestControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }


    @Test
    public void getUserList() throws Exception {
        mockMvc.perform(get("/user"))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json;charset=UTF-8")) 
            .andExpect(content().encoding("UTF-8"))
            .andExpect(jsonPath("$", hasSize(8)))
            .andExpect(jsonPath("$[0].id").exists())
            .andExpect(jsonPath("$[0].alias").exists())
            .andExpect(jsonPath("$[0].name").exists())
        );
    }
}

この単体テストは、デプロイせずにRESTインターフェースをテストします。具体的には、正確に8人のユーザーが返され、最初のユーザーにフィールド 'id'、 'alias'および 'name'があるかどうかをテストします。

JsonPathアサーションには2つの依存関係が必要です。

'com.jayway.jsonpath:json-path:0.8.1'
'com.jayway.jsonpath:json-path-assert:0.8.1'

そしておそらくまた:

'org.springframework:spring-test:4.1.7.RELEASE'
7
morsor