Unit testing 单元测试我的服务和模拟依赖项

Unit testing 单元测试我的服务和模拟依赖项,unit-testing,Unit Testing,我有一个服务,它有两个依赖项。其中之一是一个$http服务,负责对我的RESTAPI进行Ajax调用 在我的服务中,我有以下功能: this.getAvailableLoginOptions = function() { return $http.get(path.api + '/security/me/twoFA/options').then(function (resp) { return new TwoFaLoginOptions(resp.data);

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

在我的服务中,我有以下功能:

this.getAvailableLoginOptions = function() {

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

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

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

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

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

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

但是,如果其他开发人员进来重构这个函数,那么现在它从另一个源获取选项,会怎么样

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

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

我们应该将每个函数作为一个黑盒进行测试[…]还是应该进行测试 它是一个白色的盒子吗

一般来说,单元测试被视为白盒测试(模拟您的依赖关系,以获得帮助您访问各种代码路径的预定义响应,同时声明这些依赖关系已使用预期参数调用),而系统(或集成)测试将使用黑盒方法(例如,像客户端一样调用服务,针对响应/DB断言)

但是,如果其他开发人员进来重构这个函数,那么现在它从另一个源获取选项,会怎么样

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

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

我们应该将每个函数作为一个黑盒进行测试[…]还是应该进行测试 它是一个白色的盒子吗


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

感谢您的回答Alexandru。我同意我应该使用类似于
twoFaLoginOptionsFactory.getNew(xxx)
的东西,而不是
newtwofaloginoptions(xxx)
,这样我可以更轻松地模拟它。但是如果不是
$http.get(path.api+'/security/me/twoFA/options')
我重构它,使它看起来像这样:
localStorage['twoFA选项]
?在本例中,我使用完全不同的依赖关系来获取数据。那么,我应该注入
$http
localStorage
以外的内容吗?我指的是一个包装它并只提供数据的服务,我应该在这个服务中使用
$http
localStorage
…?这正是你应该做的!感谢您分享您在这个主题上的经验!谢谢你的回答。我同意我应该使用类似于
twoFaLoginOptionsFactory.getNew(xxx)
的东西,而不是
newtwofaloginoptions(xxx)
,这样我可以更轻松地模拟它。但是如果不是
$http.get(path.api+'/security/me/twoFA/options')
我重构它,使它看起来像这样:
localStorage['twoFA选项]
?在本例中,我使用完全不同的依赖关系来获取数据。那么,我应该注入
$http
localStorage
以外的内容吗?我指的是一个包装它并只提供数据的服务,我应该在这个服务中使用
$http
localStorage
…?这正是你应该做的!感谢您分享您在这个主题上的经验!