理由の1つはテスト容易性です。このクラスがあるとします:
interface HttpLoader {
String load(String url);
}
interface StringOutput {
void print(String txt);
}
@Component
class MyBean {
@Autowired
MyBean(HttpLoader loader, StringOutput out) {
out.print(loader.load("http://stackoverflow.com"));
}
}
このBeanをどのようにテストできますか?例えばこのように:
class MyBeanTest {
public void creatingMyBean_writesStackoverflowPageToOutput() {
// setup
String stackOverflowHtml = "dummy";
StringBuilder result = new StringBuilder();
// execution
new MyBean(Collections.singletonMap("https://stackoverflow.com", stackOverflowHtml)::get, result::append);
// evaluation
assertEquals(result.toString(), stackOverflowHtml);
}
}
簡単ですよね?
まだ(アノテーションが原因で)Springに依存していますが、コードを変更せずに(アノテーション定義のみ)Springへの依存を削除でき、テスト開発者はSpringがどのように機能するかについて何も知る必要はありません(とにかく彼はそうすべきですが、 Springの動作とは別にコードを確認およびテストできます)。
ApplicationContextを使用する場合でも、同じことを行うことができます。ただしApplicationContext
、巨大なインターフェースであるモックが必要です。ダミーの実装が必要か、Mockitoなどのモックフレームワークを使用できます。
@Component
class MyBean {
@Autowired
MyBean(ApplicationContext context) {
HttpLoader loader = context.getBean(HttpLoader.class);
StringOutput out = context.getBean(StringOutput.class);
out.print(loader.load("http://stackoverflow.com"));
}
}
class MyBeanTest {
public void creatingMyBean_writesStackoverflowPageToOutput() {
// setup
String stackOverflowHtml = "dummy";
StringBuilder result = new StringBuilder();
ApplicationContext context = Mockito.mock(ApplicationContext.class);
Mockito.when(context.getBean(HttpLoader.class))
.thenReturn(Collections.singletonMap("https://stackoverflow.com", stackOverflowHtml)::get);
Mockito.when(context.getBean(StringOutput.class)).thenReturn(result::append);
// execution
new MyBean(context);
// evaluation
assertEquals(result.toString(), stackOverflowHtml);
}
}
これは可能性はかなり高いですが、ほとんどの人は最初のオプションがよりエレガントでテストが簡単になることに同意するでしょう。
本当に問題がある唯一のオプションはこれです:
@Component
class MyBean {
@Autowired
MyBean(StringOutput out) {
out.print(new HttpLoader().load("http://stackoverflow.com"));
}
}
これをテストするには多大な労力が必要です。そうしないと、Beanが各テストでstackoverflowに接続しようとします。そして、ネットワーク障害が発生すると(または、過剰なアクセスレートが原因で、stackoverflowの管理者がブロックして)、ランダムに失敗するテストが発生します。
したがって、結論として、ApplicationContext
直接を使用することは自動的に間違っているとは言えず、すべてのコストで回避する必要があります。ただし、より良いオプションがある場合(そしてほとんどの場合にあります)、より良いオプションを使用してください。
new MyOtherClass()
ますか?私は@Autowiredについて知っているが、私は今までフィールド上でそれを使用しましたし、それが上壊すnew MyOtherClass()
...