Java代码测试中的澄清

时间:2013-03-13 13:41:00

标签: java spring

我已经开始阅读Spring in Action一书了。

我不了解JUnit,我认为这是我的疑问。

作者提到了一个代码片段,并说它很难测试:

package com.springinaction.knights;

public classDamselRescuingKnight implements Knight {

    private RescueDamselQuest quest;

    public DamselRescuingKnight() {
       quest = new RescueDamselQuest();
    }

    public voidembarkOnQuest() throwsQuestException {
       quest.embark();
    }
}

作者说:

为DamselRescuingKnight编写单元测试非常困难。在这样的测试中,你希望能够断言在调用骑士的embarkOnQuest()时调用任务的embark()方法。但是在这里没有明确的方法来实现这一目标。不幸的是,DamselRescuingKnight仍未经过测试。

作者的意思是什么?

为什么这里的代码难以测试?

4 个答案:

答案 0 :(得分:8)

我最初的想法是很难测试,因为“RescureDamselQuest”对象在构造函数中初始化。这使得例如插入模拟对象变得困难。模拟对象可以帮助您测试在“RescueDamselQuest”对象上调用embark()方法。

解决这个问题的更好方法是在构造函数中包含一个参数(通常我更喜欢这个方法):

public DamselRescuingKnight(RescueDamselQuest quest){
   this.quest = quest;
}

或者添加一个setter:

public void setDamselRescuingKnight(RescueDamselQuest quest){
   this.quest = quest;
}

答案 1 :(得分:2)

我给出的一个常见示例是考虑您要打开文件,解析它并获取数据类。大多数人都会这样做:

Data openAndParse(String filename) {
  ...openFile
  ...parse
}

通过这种方式,文件打开方法和解析是高度耦合的,难以测试。如果你在打开时遇到问题,解析是用解析还是打开?

通过编写JUnit测试,为简单起见,您必须执行类似......

的操作
BufferedReader openFile(String filename) {
  ...open file and return reader
}

Data parse(BufferedReader input) {
  ...parse and return data
}

JUnit引导我们找到更具凝聚力的解决方案。我们只是通过创建一个字符串,构造一个StringReader,然后是一个BufferedReader来编写JUnit测试。好吧猜怎么着?同样,我们现在可以使用parse接受来自各种来源的输入,而不仅仅是文件。

答案 2 :(得分:0)

测试很困难,因为无法换出任务实现。如果没有字节码修改,就没有简单的方法来查看是否调用了embark。

如果你可以在构造函数或setter中设置任务实现,你可以传入一个可以监视embark调用的实现。

答案 3 :(得分:0)

需要增加字段的可访问性和要测试的类的方法。例如,如果正在测试一种包私有的方法(默认),则通常位于不同包中的测试用例将无法测试此方法。因此,建议更改字段的可访问性以测试该方法。通过将 RescueDamselQuest 字段的可访问性从私有更改为默认,可以测试未使用DI的 DamselRescuingKnight 类。然后使用模仿编写测试用例。这是测试用例的代码

@Test
public void knightShouldEmbarkOnQuest() throws QuestException {


    DamselRescuingKnight knight = new DamselRescuingKnight();
    RescueDamselQuest quest = mock(RescueDamselQuest.class);
    knight.quest = quest;
    knight.embarkOnQuest();
    verify(quest, times(1)).embark();
}

并且在DamselRescuingKnight类中进行了更改以删除私有辅助功能的行

RescueDamselQuest quest;