Spring中的代码:
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnightTest {
@Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
BraveKnight knight = new BraveKnight(mockQuest);
knight.embarkOnQuest();
verify(mockQuest, times(1)).embark();
}
}我理解依赖注入的用法,它允许我们在不修改依赖代码的情况下切换实现。
书中说“编写单元测试非常困难……”。
然而,我不能理解在没有依赖注入的情况下进行单元测试是多么困难!我的直觉拒绝合作!
你能开始为类"DamselRescuingKnight“和任何其他更好的示例类(没有DI)编写junit/单元测试,让我认识到DI使单元测试更容易的点/阶段吗?
发布于 2016-03-21 05:40:53
当您尝试测试DamselRescuingKnight时,上述示例中的困难就出现了。假设,你想测试那个(见下文)
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class DamselRescuingKnightTest {
@Test
public void knightShouldEmbarkOnQuest() {
DamselRescuingKnight knight = new DamselRescuingKnight ();
knight.embarkOnQuest();
// now what?
}
}您如何确定knight.embarkOnQuest()确实做了任何事情?答案是你不能,因为你不能访问内部使用的quest实例。
现在,为了能够测试这样的类,您需要向Knight添加一个getQuest()方法,然后向Quest添加一个isEmbarked()方法。公平地说,这个例子非常简单,因为骑士只调用没有参数的任务,没有其他的。如果骑士想要与一个任务互动,并从铁匠那里得到一些武器,那么你也需要以某种方式允许访问它。你也许可以做所有的样板来完成这件事。但是,假设您正在向blacksmith传递参数-如何确保传递的参数是正确的?或者你如何确保骑士在去任务之前拿到他/她的武器?
这就是依赖注入的用武之地。您可以只创建mock (通过使用mock框架,或者通过实现您自己的mock),这样您就可以验证您的骑士是否做了预期的事情。
发布于 2016-03-21 05:38:22
当然,问题出在quest变量。您希望以某种方式检查是否调用了embark()方法。如果不能用模拟实例替换它,这是非常困难的。
如果变量是protected而不是private,则测试用例可以通过驻留在同一个包中来覆盖它。
您还可以使用面向方面的编程来替换变量。
但最简单的是如果代码是从一开始就使用依赖注入编写的。
您要求了解如何使用AOP。下面是一个AspectJ切入点的示例,您可以在单元测试中使用它将RescueDamselQuest实例替换为一个名为MockRescueDamselQuest的模拟实例(很抱歉,我没有完全正确地理解语法,因为我使用AspectJ已经有一段时间了):
aspect MockRescueDamselQuestInstantiations {
RescueDamselQuest around (): call(RescueDamselQuest.new()) {
return new MockRescueDamselQuest();
}
}这将捕获RescueDamselQuest的任何实例化(即对new RescueDamselQuest()的调用),并返回一个MockRescueDamselQuest对象。
考虑到这个需求需要更多的连接,我强烈建议使用依赖注入来代替!
发布于 2018-12-02 11:58:33
当我在Spring in Action中阅读这篇文章时,这也让我感到困惑。读完上面的答案后,我想补充说,当不使用DI时,Junit方法需要调用私有对象的方法(在accessible中),并且这个对象请求是在DamselRescuingKnight的构造函数中创建的,所以不能编写embarkQuest()的测试用例。相反,当使用DI时,您将对象创建外部化,Junit方法可以创建该对象,以便它可以访问该对象,然后可以测试emabarkQuest(),这最终需要测试quest方法
https://stackoverflow.com/questions/36119821
复制相似问题