原因之一是可测试性。假设您有这个课程:
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"));
}
}
您如何测试该豆?例如:
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()
..