Một trong những lý do là khả năng kiểm tra. Nói rằng bạn có lớp này:
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"));
}
}
Làm thế nào bạn có thể kiểm tra đậu này? Ví dụ như thế này:
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);
}
}
Dễ thôi phải không?
Mặc dù bạn vẫn phụ thuộc vào Spring (do các chú thích), bạn có thể loại bỏ sự phụ thuộc của mình vào mùa xuân mà không thay đổi bất kỳ mã nào (chỉ các định nghĩa chú thích) và nhà phát triển thử nghiệm không cần biết gì về cách hoạt động của mùa xuân nó cho phép xem xét và kiểm tra mã riêng biệt với những gì mùa xuân làm).
Vẫn có thể làm tương tự khi sử dụng ApplicationContext. Tuy nhiên, sau đó bạn cần phải giả định ApplicationContext
đó là một giao diện lớn. Bạn có thể cần một triển khai giả hoặc bạn có thể sử dụng khung mô phỏng như 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);
}
}
Đây là một khả năng hoàn toàn, nhưng tôi nghĩ hầu hết mọi người sẽ đồng ý rằng tùy chọn đầu tiên thanh lịch hơn và làm cho thử nghiệm đơn giản hơn.
Tùy chọn duy nhất thực sự là một vấn đề là cái này:
@Component
class MyBean {
@Autowired
MyBean(StringOutput out) {
out.print(new HttpLoader().load("http://stackoverflow.com"));
}
}
Kiểm tra điều này đòi hỏi những nỗ lực lớn hoặc bean của bạn sẽ cố gắng kết nối với stackoverflow trên mỗi thử nghiệm. Và ngay khi bạn gặp lỗi mạng (hoặc quản trị viên tại stackoverflow chặn bạn do tốc độ truy cập quá cao), bạn sẽ có các thử nghiệm thất bại ngẫu nhiên.
Vì vậy, như một kết luận, tôi sẽ không nói rằng sử dụng ApplicationContext
trực tiếp là tự động sai và nên tránh bằng mọi giá. Tuy nhiên nếu có các tùy chọn tốt hơn (và trong hầu hết các trường hợp), thì hãy sử dụng các tùy chọn tốt hơn.
new MyOtherClass()
đối tượng? Tôi biết về @Autowired, nhưng tôi chỉ từng sử dụng nó trên các lĩnh vực và nó bị hỏng vàonew MyOtherClass()
..