【问题标题】:Unit testing my service and mocking dependencies单元测试我的服务和模拟依赖项
【发布时间】:2016-06-16 16:37:32
【问题描述】:

我有一个有两个依赖项的服务。其中之一是 $http 服务,负责对我的 Rest API 进行 Ajax 调用。

在我的服务中,我有这个功能:

this.getAvailableLoginOptions = function() {

    return $http.get(path.api + '/security/me/twoFA/options').then(function (resp) {
        return new TwoFaLoginOptions(resp.data);
    });

};

此函数从我的 API 中获取一些选项并返回一个对象。

现在,我应该如何正确地对该函数进行单元测试?通常我只会模拟 $http 服务,这样当调用 get 函数并使用以 '/security/me/twoFA/options' 结尾的字符串参数时,我会返回带有选项的有效响应。

但是,如果其他开发人员进来并重构此函数,那么现在它会从另一个源 e.i. 中获取选项。另一个 API 或浏览器的本地存储,但该函数仍然可以完美运行,因为它返回了它应该执行的操作。

那么真正的单元测试是什么?我们是否应该将每个函数测试为一个黑盒,并假设如果我们提供一些输入,那么我们期望一些特定的输出,或者我们应该通过查看函数内的每一行代码并模拟所有内容来将其测试为一个白盒,但测试将是强烈依赖于所有依赖项以及我使用它们的方式。

是否可以编写一个单元测试来测试我的函数是否正常工作,无论使用什么算法或数据源来实现它?或者这实际上是单元测试的一部分,用于检查我的函数是否真的以这种和那种方式使用依赖项(除了测试函数的逻辑)?

【问题讨论】:

    标签: unit-testing


    【解决方案1】:

    但是如果其他开发人员进来并重构这个函数,所以现在它从另一个来源获取选项

    这正是使用Dependency Injection的原因,因为它使管理对象之间的依赖关系变得简单(更容易将连贯的功能分解为单独的契约(接口),从而解决在运行时交换对象依赖关系的问题或编译时间)。

    例如,您可以拥有一个具有多个实现(服务、本地存储等)的 ITwoFaLoginOptions,然后您将模拟接口 get 方法。

    我们应该将每个功能都作为黑盒进行测试 [...] 还是应该进行测试 它是一个白盒子吗?

    一般来说,单元测试被认为是白盒测试(模拟你的依赖以获得预定义的响应,帮助你到达各种代码路径,同时也断言这些依赖项已使用预期参数调用),而系统(或集成)测试将使用黑盒方法(例如像客户端一样调用服务,针对响应/数据库)。

    【讨论】:

    • 感谢您的回答 Alexandru。我同意我应该使用twoFaLoginOptionsFactory.getNew(xxx) 之类的东西而不是new TwoFaLoginOptions(xxx),这样我可以更轻松地模拟它。但是,如果我重构它而不是 $http.get(path.api + '/security/me/twoFA/options'),那么它看起来像这样:localStorage['twoFaOptions']?在这种情况下,我使用完全不同的依赖项来获取数据。那么我应该注入$httplocalStorage 以外的其他东西吗?我的意思是一个包装它并只提供数据的服务,并且只有在这个服务内部我应该使用$httplocalStorage...?
    • 正是你应该怎么做!
    • 感谢您分享您在此主题上的经验!
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 2016-08-02
    • 2013-07-07
    相关资源
    最近更新 更多