5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SpringでDIされるオブジェクトのMockテスト その3 Controller

Last updated at Posted at 2015-04-28

「SpringでDIされるオブジェクトのMockテスト」
「SpringでDIされるオブジェクトのMockテスト その2」の続きです。

前回は単純なAutowiredでしたが、今回はControllerのテストを対象にします。こんな感じのものが対象です。

@RestController
class ControllerA{

    @Autowired
    ServiceB serviceB;
    
    @Autowired
    ServiceC serviceC;
    
    @RequestMapping(value = "/order", method = RequestMethod.GET)
    public Map order1(@Valid String item){
    	return serviceB.save(item);
    }
}

(注意)実際に試したコードは業務で使っているコードなので公開できません。考え方の参考にするためにこんな感じで考えましたという程度の情報ですので、その点はご了承ください。

テストコードはgroovyのSpockFramework使ってます。

やったこと

Mockテスト用のcontext.xmlを用意し、ServiceBに対してMockをInjectionするようにしました。

context-apimock.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
       ">

    <!-- 本物をComponent-Scanの対象から外す -->
    <context:component-scan base-package="nyasba.example.service">
        <context:exclude-filter type="aspectj" expression="nyasba.example.ServiceB*" />
    </context:component-scan>

    <!-- Mockを生成する -->
    <bean id="serviceBMock" name="serviceBMock" class="org.mockito.Mockito"
          factory-method="mock">
        <constructor-arg value="nyasba.example.service.ServiceB"/>
    </bean>
    
    <!-- その他は省略 -->
</beans>

テストコード

@WebAppConfiguration
@ContextConfiguration(locations = "classpath:context-apimock.xml")
class ControllerAMockSpec extends Specification {

    @Autowired
    ServiceB serviceBMock;

    @Autowired
    WebApplicationContext wac;

    MockMvc mockMvc;

    def test() {
    
        setup:
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        
        // serviceBのsaveが呼ばれるとException発生するようにする
        Mockito.when(serviceBMock.save(Mockito.any(String.class)))
                .thenThrow(new RuntimeException("あうとーーー!"))

        when:
        ResultActions resultActions = mockMvc.perform(post("/order").param("item", "test"))

        then:
        // 省略
                                      
        cleanup:
        Mockito.reset(serviceBMock)
        
    }
}

他に試したこと

いずれも失敗。

  • AutowiredしたControllerに対してServiceBのMockを強制的に置き換えた
  • AutowiredしたContorollerから MockMvcBuilders.standaloneSetup(controller) を使い、mockMvcを作成し、Mockを強制的に置き換えた

業務で使っているコードはAOPを使っているので、Proxyでwrapされたオブジェクトになるので、そのあたりも何か影響しているのかもしれません。。AOP使ってないなら@InjectMockとかでもいけるかもです。

感想

SpringのDIの仕組みはまだまだ全然理解出来たといえるレベルにないですが、こういうのきっかけで作りを調べるのは勉強になるのでよかったです。

5
7
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
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?