没有依赖注入的单元测试

use*_*309 4 java junit spring unit-testing dependency-injection

来自 Spring in Action 的代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我理解依赖注入的使用,它允许我们在不修改依赖代码的情况下切换实现。

这本书说“编写单元测试非常困难......”。

但是,我无法理解没有依赖注入的单元测试将是多么困难!我的直觉拒绝合作!

您能否开始为“DamselRescuingKnight”类和任何其他更好的示例类(没有 DI)编写 junit/单元测试,让我意识到 DI 使单元测试更容易的点/阶段?

Mat*_*tar 5

当您尝试测试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?            
    }
}
Run Code Online (Sandbox Code Playgroud)

你怎么能确定 Knight.embarkOnQuest() 确实做了什么?答案是你不能,因为你不能访问它内部使用的任务实例。

现在为了能够测试这样的类,您将向getQuest()Knight添加一个方法,然后isEmbarked()向 Quest添加一个方法。平心而论,这个例子很简单,因为骑士只调用了没有参数的任务,没有别的。如果骑士会与任务互动并从铁匠那里获得一些武器,那么您也需要以某种方式允许访问。你可能可以做所有的样板来完成它。但是然后假设,您正在将参数传递给铁匠 - 您如何确保传递的参数是正确的?或者你如何确保骑士去任务之前拿到他/她的武器?

这就是依赖注入发挥作用的地方。您可以创建模拟(通过使用模拟框架,或通过实现您自己的模拟),以便您可以验证您的骑士是否执行了预期的操作。

  • 我可以说我们不应该测试实现细节。事实上 DamselRescuingKnightTest 在内部使用 Quest 对象是一个实现细节。相反,我们应该只测试公共 API。因此,大概 DamselRescuingKnightTest 还有一些其他方法,例如“getQuestResult()”,我们将测试这些方法。 (3认同)