web-dev-qa-db-ja.com

単体テスト:モック動作を定義した後に@PostConstructを呼び出します

私には2つのクラスがあります。

public MyService {
    @Autowired
    private MyDao myDao;     
    private List<Items> list; 

    @PostConstruct
    private void init(){
         list = myDao.getItems(); 
    }
}

ここで、ユニットテストにMyServiceを関与させたいので、MyDaoの動作を模擬します。

XML:

<bean class = "com.package.MyService"> 
<bean  class="org.mockito.Mockito" factory-method="mock"> 
     <constructor-arg value="com.package.MyDao"/>
</bean>

<util:list id="responseItems" value-type="com.package.Item">
    <ref bean="item1"/>
    <ref bean="item2"/>
</util:list>

単体テスト:

@ContextConfiguration("/test-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {

    @Autowired 
    MyService myService

    @Autowired 
    MyDao myDao;

    @Resource
    @Qualifier("responseItems")
    private List<Item> responseItems; 

    @Before
    public void setupTests() {
        reset(myDao); 
        when(myDao.getItems()).thenReturn(responseItems); 
    }
}

これの問題は、MyService Beanが作成され、モックされた動作が定義される前に@PostConstruct Beanが呼び出されることです。

XMLでモック動作を定義するか、または@PostConstruct単体テストのセットアップ後まで?

11
dwjohnston

私のプロジェクトでも同じような要件があります。 @PostConstructorを使用して文字列を設定する必要があり、Springコンテキストを実行したくない、つまり簡単なモックが必要な場合。私の要件は次のとおりです:

public class MyService {

@Autowired
private SomeBean bean;

private String status;

@PostConstruct
private void init() {
    status = someBean.getStatus();
} 

}

解決:

public class MyServiceTest(){

@InjectMocks
private MyService target;

@Mock
private SomeBean mockBean;

@Before
public void setUp() throws NoSuchMethodException,  InvocationTargetException, IllegalAccessException {

    MockitoAnnotations.initMocks(this);

    when(mockBean.getStatus()).thenReturn("http://test");

    //call post-constructor
    Method postConstruct =  MyService.class.getDeclaredMethod("init",null); // methodName,parameters
    postConstruct.setAccessible(true);
    postConstruct.invoke(target);
  }

}
12
SS02

MyDaoは、外部システムの抽象化のように聞こえます。一般に、外部システムは_@PostConstruct_メソッドで呼び出すべきではありません。代わりに、MyService内の別のメソッドによってgetItems()を呼び出します。

MockitoインジェクションはSpringの開始後に行われ、その時点ではモックは機能していません。 _@PostConstruct_を遅らせることはできません。これに打ち勝ち、ロードを自動的に実行するには、MyService実装SmartLifecycleを使用し、getItems()start()を呼び出します。

3
UserF40