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が推奨するアプローチであるSpringClassRuleSpringMethodRuleを使用した例を確認しました。

この記事ではパラメーター化されたランナーについてのみ説明しましたが、実際にはこれらのアプローチのいずれかを任意のJUnitランナーで使用してSpring統合テストを作成できます。

いつものように、すべてのサンプルコードはGitHubで入手できます。