首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无依赖注入的单元测试

无依赖注入的单元测试
EN

Stack Overflow用户
提问于 2016-03-21 05:27:58
回答 3查看 3.9K关注 0票数 4

Spring中的代码:

代码语言:javascript
复制
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使单元测试更容易的点/阶段吗?

EN

回答 3

Stack Overflow用户

发布于 2016-03-21 05:40:53

当您尝试测试DamselRescuingKnight时,上述示例中的困难就出现了。假设,你想测试那个(见下文)

代码语言:javascript
复制
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),这样您就可以验证您的骑士是否做了预期的事情。

票数 5
EN

Stack Overflow用户

发布于 2016-03-21 05:38:22

当然,问题出在quest变量。您希望以某种方式检查是否调用了embark()方法。如果不能用模拟实例替换它,这是非常困难的。

如果变量是protected而不是private,则测试用例可以通过驻留在同一个包中来覆盖它。

您还可以使用面向方面的编程来替换变量。

但最简单的是如果代码是从一开始就使用依赖注入编写的。

您要求了解如何使用AOP。下面是一个AspectJ切入点的示例,您可以在单元测试中使用它将RescueDamselQuest实例替换为一个名为MockRescueDamselQuest的模拟实例(很抱歉,我没有完全正确地理解语法,因为我使用AspectJ已经有一段时间了):

代码语言:javascript
复制
aspect MockRescueDamselQuestInstantiations {
    RescueDamselQuest around (): call(RescueDamselQuest.new()) {
        return new MockRescueDamselQuest();
    }
}

这将捕获RescueDamselQuest的任何实例化(即对new RescueDamselQuest()的调用),并返回一个MockRescueDamselQuest对象。

考虑到这个需求需要更多的连接,我强烈建议使用依赖注入来代替!

票数 2
EN

Stack Overflow用户

发布于 2018-12-02 11:58:33

当我在Spring in Action中阅读这篇文章时,这也让我感到困惑。读完上面的答案后,我想补充说,当不使用DI时,Junit方法需要调用私有对象的方法(在accessible中),并且这个对象请求是在DamselRescuingKnight的构造函数中创建的,所以不能编写embarkQuest()的测试用例。相反,当使用DI时,您将对象创建外部化,Junit方法可以创建该对象,以便它可以访问该对象,然后可以测试emabarkQuest(),这最终需要测试quest方法

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36119821

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档