私のアプリケーションには、多くの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が組み込まれています)。
手伝ってくれてありがとう!
ドキュメントにはこれに関する良い 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";
}
};
}
}
エンドツーエンド(統合)テストを探していなかった場合は、MockRestServiceServer
が役立ちます。テストケースを実際のサービスから切り離すことは非常に便利だとわかりました。
春のドキュメントは言った:
RestTemplateの直接または間接的な使用を伴うテストに使用されます。 RestTemplateを介して実行される予想されるリクエストと、そのために返信するためのモック応答をセットアップする方法を提供します実際のサーバーの必要性を取り除く。
もう1つのヒントは、requestTo
を自動的にインポートできないことです。
server.expect(manyTimes(), requestTo("/hotels/42")) ....
org.springframework.test.web.client.match.MockRestRequestMatchers
の静的メソッドです
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'