LoginSignup
2
2

More than 5 years have passed since last update.

jersey+springでリソースクラスのユニットテスト(サービスクラスをモックで注入)

Last updated at Posted at 2015-02-19

理屈はわからないが、How toのメモとして。

次のようなサービスクラスをspringで注入しているリソースクラスのユニットテストをしたい。
となると、サービスのところをモックにして注入したい。HK2で注入してるときのやり方はわかったが、それだとここの実装をかえなきゃいけないので、微妙。試行錯誤して、とりあえずできたやり方を紹介。もっと自然なやり方があればコメントなどお願いします。

HogeResource.java
@Resource
@Path("hoge")
public class HogeResource {

    @Autowired
    private HogeService service;

   /* 以下略 */

下記のようなテストの基底クラスをつくる。
JerseyTestは継承しないでRuleにした方がやりやすい。(というか、そうしないとうまくいかなかった。設定かぶってる感があるが・・・)

TestBase.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestResourceConfig.class, HogeServiceMock.class})
public class AttachementResourceTestBase {

    @Autowired
    protected HogeService mockService; 

    @Rule
    public JerseyTestResource testResource = new JerseyTestResource(new TestResourceConfig());

}

下記のをそのまんまつかわしていただきました。
http://qiita.com/opengl-8080/items/f90582f6e5cd9db4972b

JerseyTestResource.java
public class JerseyTestResource extends ExternalResource {

    private JerseyTest jerseyTest;

    public JerseyTestResource(final Application config) {
        this.jerseyTest = new JerseyTest() {
            @Override
            protected Application configure() {
                return config;
            }
        };
    }

    @Override
    public void before() throws Throwable {
        this.jerseyTest.setUp();
    }

    @Override
    public void after() {
        try {
            this.jerseyTest.tearDown();
        } catch (Exception e) {
            throw new RuntimeException("failed to tear down JerseyTest.", e);
        }
    }

    public JerseyTest getJerseyTest() {
        return this.jerseyTest;
    }

}

次のクラスで、サービスクラスに注入をモックにしている模様。あとで振る舞いを決めるために呼び出すので、static なインスタンスを注入している。(context.xmlのbeanタグに相当??)

HogeServiceMock.java
@Configuration
public class HogeServiceMock {

    public static HogeService mockService = Mockito.mock(HogeService.class);

    @Bean
    public HogeService hogeService() {
        return mockService;
    }

}

テストはEnclosedランナーを使って構造化。モックはひとつのインスタンスを使いまわしているので、afterでリセットしないと、呼び出し回数がコントロールできないのに注意。

URIをたたくのは、JerseyTestのtarget()を@Ruleをつけたフィールドから取得して、そいつにさせている。

HogeResourceTest.java
@RunWith(Enclosed.class)
public class HogeResourceTest {

    @RunWith(Enclosed.class)
    public static class 失敗 {

        public static class IDが存在しない extends TestBase {

            @Before
            public void setUp() throws IOException {
                when(mockService.findById(anyInt()).thenReturn(null);
            }

            @After
            public void tearDown() {
                reset(mockService);
            }

            @Test
            public void ステータスコードはNOT_FOUND() throws IOException {
                WebTarget target = testResource.getJerseyTest().target();

               int status = target.path("hoge/123").request().get().getStatus();

               verify(mockService, times(1)).findById(123);

               assertThat(status, is(NOT_FOUND.getStatusCode()));
            }
        }

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2