私はこれに似た豆を持っています:
@Service
public class A {
@Autowired
private B b;
@PostConstruct
public void setup() {
b.call(param);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class, Config.class })
@WebIntegrationTest(randomPort = true)
public class Test {
@Autowired
B b;
@Before
public void setUp() throws Exception {
when(b.call(any())).thenReturn("smth");
}
@Test
public void test() throws Exception {
// test...
}
}
問題は、テストの実行時にPostConstruct
がsetUp
の前に呼び出されることです。
nitA
のテストを記述したい場合は、Springを使用しないでください。代わりに、A
を自分でインスタンス化し、B
のスタブ/モックを渡します(コンストラクターインジェクションまたはReflectionTestUtils
を使用してプライベートフィールドを設定します)。
例えば:
@Service
public class A {
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
@PostConstruct
public void setup() {
b.call(param);
}
}
-
public class Test {
@Test
public void test() throws Exception {
B b = mock(b);
A a = new A(b);
// write some tests for A
}
}
integrationテストを記述したいため、Springを使用する必要がある場合は、別のアプリケーションコンテキストを使用して、B
をスタブ/モックに置き換えます。
たとえば、B
が次のようにProduction
クラスでインスタンス化されると仮定します。
@Configuration
public class Production {
@Bean
public B b() {
return new B();
}
}
テスト用に別の@Configuration
クラスを作成します。
@Configuration
public class Tests {
@Bean
public B b() {
// using Mockito is just an example
B b = Mockito.mock(B.class);
Mockito.when(b).thenReturn("smth");
return b;
}
}
テストでは、@SpringApplicationConfiguration
アノテーションを使用して参照してください。
@SpringApplicationConfiguration(classes = { Application.class, Tests.class })
もう1つの方法は、テストでアプリケーションコンテキストを自分でインスタンス化し、コンテキストを更新する前にモックを挿入することです。たとえば、次のようになります。
@Configuration
@ComponentScan
public class TestConfiguration {}
...
ClassToMock mock = mock(ClassToMock.class);
AnnotationConfigApplicationContext c = new AnnotationConfigApplicationContext();
c.getDefaultListableBeanFactory().registerResolvableDependency(
ClassToMock.class,
mock);
c.register(TestConfiguration.class);
c.refresh();
この代替手段は、コンテキストに@PostConstruct
アノテーションがあり、事前にモックに期待値を設定する場合に役立ちます。