Sebeplerden biri test edilebilirliktir. Diyelim ki bu sınıfa sahipsiniz:
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"));
}
}
Bu fasulyeyi nasıl test edebilirsiniz? Örneğin şöyle:
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);
}
}
Kolay değil mi?
Hala Spring'e (ek açıklamalardan dolayı) bağlıyken, herhangi bir kodu değiştirmeden (sadece ek açıklama tanımları) bahar bağımlılığını kaldırabilirsiniz ve test geliştiricisinin baharın nasıl çalıştığı hakkında bir şey bilmesine gerek yoktur (belki de yine de yapmalıdır, ancak kodu, yayın ne yaptığından ayrı olarak incelemeye ve test etmeye izin verir).
ApplicationContext'i kullanırken de aynısını yapmak hala mümkündür. Ancak o zaman ApplicationContext
büyük bir arayüz olan sahte gerekir . Kukla bir uygulamaya ihtiyacınız var veya Mockito gibi bir alaycı çerçeve kullanabilirsiniz:
@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);
}
}
Bu oldukça bir olasılık, ama çoğu insanın ilk seçeneğin daha zarif olduğunu ve testi basitleştirdiğini kabul edeceğini düşünüyorum.
Gerçekten sorun olan tek seçenek budur:
@Component
class MyBean {
@Autowired
MyBean(StringOutput out) {
out.print(new HttpLoader().load("http://stackoverflow.com"));
}
}
Bunu test etmek büyük çaba gerektirir veya fasulyeniz her testte yığın akışına bağlanmaya çalışır. Ve bir ağ arızanız olur olmaz (veya yığın akışındaki yöneticiler aşırı erişim oranı nedeniyle sizi engeller) rastgele başarısız testlere sahip olursunuz.
Sonuç olarak, ApplicationContext
doğrudan kullanmanın otomatik olarak yanlış olduğunu ve ne pahasına olursa olsun kaçınılması gerektiğini söylemem. Ancak, daha iyi seçenekler varsa (ve çoğu durumda), daha iyi seçenekleri kullanın.
new MyOtherClass()
? Ben @Autowired hakkında biliyorum, ama ben sadece tarlalarda kullandım ve kırılıyornew MyOtherClass()
..