1. 概要
このチュートリアルでは、JUnit4に実装されているSpring統合テストをParameterizedJUnitテストランナーでパラメーター化する方法を説明します。
2. SpringJUnit4ClassRunner
SpringJUnit4ClassRunner は、JUnit4の ClassRunner の実装であり、はSpringのTestContextManagerをJUnitテストに組み込みます。
TestContextManager は、Spring TestContext フレームワークへのエントリポイントであるため、Spring ApplicationContextへのアクセスとJUnitテストクラスの依存性注入を管理します。 したがって、 SpringJUnit4ClassRunner を使用すると、開発者はコントローラーやリポジトリなどのSpringコンポーネントの統合テストを実装できます。
たとえば、RestControllerの統合テストを実装できます。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
public class RoleControllerIntegrationTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
private static final String CONTENT_TYPE = "application/text;charset=ISO-8859-1";
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void givenEmployeeNameJohnWhenInvokeRoleThenReturnAdmin() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders
.get("/role/John"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE))
.andExpect(MockMvcResultMatchers.content().string("ADMIN"));
}
}
テストからわかるように、コントローラーは、パスパラメーターとしてユーザー名を受け入れ、それに応じてユーザーロールを返します。
ここで、異なるユーザー名/役割の組み合わせでこのRESTサービスをテストするには、新しいテストを実装する必要があります:
@Test
public void givenEmployeeNameDoeWhenInvokeRoleThenReturnEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders
.get("/role/Doe"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE))
.andExpect(MockMvcResultMatchers.content().string("EMPLOYEE"));
}
このは、多数の入力の組み合わせが可能なサービスではすぐに手に負えなくなる可能性があります。
テストクラスでこの種の繰り返しを回避するために、パラメータ化を使用して複数の入力を受け入れるJUnitテストを実装する方法を見てみましょう。
3. パラメータ化の使用
3.1. パラメータの定義
Parameterized は、カスタムJUnitテストランナーであり、単一のテストケースを記述して、複数の入力パラメーターに対して実行することができます。
@RunWith(Parameterized.class)
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
public class RoleControllerParameterizedIntegrationTest {
@Parameter(value = 0)
public String name;
@Parameter(value = 1)
public String role;
@Parameters
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList();
params.add(new Object[]{"John", "ADMIN"});
params.add(new Object[]{"Doe", "EMPLOYEE"});
return params;
}
//...
}
上に示したように、 @Parameters アノテーションを使用して、JUnitテストに注入する入力パラメーターを準備しました。 これらの値のマッピングは、@Parameterフィールドnameおよびrole。にも提供されています。
しかし、今、解決すべき別の問題があります— JUnitは、1つのJUnitテストクラスで複数のランナーを許可しません。 これは、SpringJUnit4ClassRunnerを利用してTestContextManagerをテストクラスに埋め込むことができないことを意味します。 TestContextManagerを埋め込む別の方法を見つける必要があります。
幸い、Springにはこれを実現するためのいくつかのオプションがあります。 これらについては、次のセクションで説明します。
3.2. TestContextManagerを手動で初期化する
SpringではTestContextManagerを手動で初期化できるため、最初のオプションは非常に単純です。
@RunWith(Parameterized.class)
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
public class RoleControllerParameterizedIntegrationTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
private TestContextManager testContextManager;
@Before
public void setup() throws Exception {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
//...
}
特に、この例では、 パラメータ化の代わりにランナー SpringJUnit4ClassRunner。 次に、初期化しました TestContextManager の中に設定() 方法。
これで、パラメーター化されたJUnitテストを実装できます。
@Test
public void givenEmployeeNameWhenInvokeRoleThenReturnRole() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders
.get("/role/" + name))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE))
.andExpect(MockMvcResultMatchers.content().string(role));
}
JUnitはこのテストケースを2回実行します— @Parametersアノテーションを使用して定義した入力のセットごとに1回。
3.3. SpringClassRuleおよびSpringMethodRule
通常、TestContextManagerを手動で初期化することはお勧めしません。 代わりに、SpringはSpringClassRuleおよびSpringMethodRule。を使用することをお勧めします
SpringClassRule は、JUnitの TestRule —テストケースを作成する別の方法を実装します。 TestRule を使用して、以前に @ Before、 @ BeforeClass、@ After、、および @AfterClass[ X174X]メソッド。
SpringClassRule は、TestContextManagerのクラスレベルの機能をJUnitテストクラスに埋め込みます。 初期化されます TestContextManager 春のセットアップとクリーンアップを呼び出します TestContext。 したがって、依存性注入とへのアクセスを提供します ApplicationContext 。
SpringClassRule に加えて、SpringMethodRuleも使用する必要があります。 これは、TestContextManager。のインスタンスレベルおよびメソッドレベルの機能を提供します。
SpringMethodRule は、テストメソッドの準備を担当します。 また、スキップのマークが付けられたテストケースをチェックし、実行されないようにします。
テストクラスでこのアプローチを使用する方法を見てみましょう。
@RunWith(Parameterized.class)
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
public class RoleControllerParameterizedClassRuleIntegrationTest {
@ClassRule
public static final SpringClassRule scr = new SpringClassRule();
@Rule
public final SpringMethodRule smr = new SpringMethodRule();
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
//...
}
4. 結論
この記事では、SpringJUnit4ClassRunnerの代わりにParameterizedテストランナーを使用してSpring統合テストを実装する2つの方法について説明しました。 TestContextManager を手動で初期化する方法と、Springが推奨するアプローチであるSpringClassRuleとSpringMethodRuleを使用した例を確認しました。
この記事ではパラメーター化されたランナーについてのみ説明しましたが、実際にはこれらのアプローチのいずれかを任意のJUnitランナーで使用してSpring統合テストを作成できます。
いつものように、すべてのサンプルコードはGitHubで入手できます。