我正在使用mocha来单元测试为node.js编写的应用程序
我想知道是否可以对未在模块中导出的单元测试功能进行单元测试。
例:
我在foobar.js
中有很多这样定义的函数
function private_foobar1(){
...
}
function private_foobar2(){
...
}
以及一些出口为公共的功能:
exports.public_foobar3 = function(){
...
}
测试用例的结构如下:
describe("private_foobar1", function() {
it("should do stuff", function(done) {
var stuff = foobar.private_foobar1(filter);
should(stuff).be.ok;
should(stuff).....
显然这不起作用,因为private_foobar1
没有出口。
对私有方法进行单元测试的正确方法是什么?摩卡有没有一些内置的方法呢?
如果模块未导出该功能,则模块外部的测试代码无法调用该功能。这是由于JavaScript如何工作,而Mocha本身无法绕过这一点。
在我确定测试私有函数是正确的事情的少数情况下,我所做的是设置一些环境变量,我的模块检查它以确定它是否在测试设置中运行。如果它在测试设置中运行,那么它会导出我可以在测试期间调用的其他函数。
这里使用了“环境”这个词。这可能意味着检查process.env
或其他可以与模块进行通信的“你现在正在接受测试”。我必须这样做的实例是在RequireJS环境中,我为此目的使用了module.config
。
看看rewire模块。它允许您获取(和操作)模块中的私有变量和函数。
所以在你的情况下,用法将是这样的:
var rewire = require('rewire'),
foobar = rewire('./foobar'); // Bring your module in with rewire
describe("private_foobar1", function() {
// Use the special '__get__' accessor to get your private function.
var private_foobar1 = foobar.__get__('private_foobar1');
it("should do stuff", function(done) {
var stuff = private_foobar1(filter);
should(stuff).be.ok;
should(stuff).....
Here is a really good workflow to test your private methods由Google工程师Philip Walton在其博客上解释。
_
标记它然后使用构建任务或您自己的构建系统(例如grunt-strip-code)来剥离生产构建的集合。
您的测试版本可以访问您的私有API,而您的生产版本则没有。
把你的代码写成:
var myModule = (function() {
function foo() {
// private function `foo` inside closure
return "foo"
}
var api = {
bar: function() {
// public function `bar` returned from closure
return "bar"
}
}
/* test-code */
api._foo = foo
/* end-test-code */
return api
}())
还有那样的笨拙的任务
grunt.registerTask("test", [
"concat",
"jshint",
"jasmine"
])
grunt.registerTask("deploy", [
"concat",
"strip-code",
"jshint",
"uglify"
])
In a later article,它解释了“测试私人方法”的“原因”
如果您希望保持简单,只需导出私有成员,但明确地与公共API分开一些约定,例如用_
作为它们的前缀,或者将它们嵌套在一个私有对象下。
var privateWorker = function() {
return 1
}
var doSomething = function() {
return privateWorker()
}
module.exports = {
doSomething: doSomething,
_privateWorker: privateWorker
}
我为此目的制作了一个npm包,你可能会发现它很有用:require-from
基本上,您通过以下方式公开非公共方法:
module.testExports = {
private_foobar1: private_foobar1,
private_foobar2: private_foobar2,
...
}
注意:testExports
可以是您想要的任何有效名称,当然除了exports
。
从另一个模块:
var requireFrom = require('require-from');
var private_foobar1 = requireFrom('testExports', './path-to-module').private_foobar1;
我添加了一个额外的函数,我将其命名为Internal()并从那里返回所有私有函数。然后导出此Internal()函数。例:
function Internal () {
return { Private_Function1, Private_Function2, Private_Function2}
}
// Exports --------------------------
module.exports = { PublicFunction1, PublicFunction2, Internal }
您可以像这样调用内部函数:
let test = require('.....')
test.Internal().Private_Function1()
我最喜欢这个解决方案,因为:
我跟着@barwin回答并检查了如何使用重新接线模块进行单元测试。我可以确认这个解决方案很有效。
该模块应分为两部分 - 公共部分和私有部分。对于公共功能,您可以以标准方式执行此操作:
const { public_foobar3 } = require('./foobar');
对于私人范围:
const privateFoobar = require('rewire')('./foobar');
const private_foobar1 = privateFoobar .__get__('private_foobar1');
const private_foobar2 = privateFoobar .__get__('private_foobar2');
为了更多地了解这个主题,我创建了一个包含完整模块测试的工作示例,测试包括私有和公共范围。
有关详细信息,我建议您查看完整描述主题的文章(https://medium.com/@macsikora/how-to-test-private-functions-of-es6-module-fb8c1345b25f),其中包括代码示例。
我知道这不一定是你正在寻找的答案,但我发现大多数时候,如果一个私有函数值得测试,它值得存在于自己的文件中。
例如。而不是像公共文件一样在同一个文件中使用私有方法,比如这样......
SRC /事/ PublicInterface.js
function helper1 (x) {
return 2 * x;
}
function helper2 (x) {
return 3 * x;
}
export function publicMethod1(x) {
return helper1(x);
}
export function publicMethod2(x) {
return helper1(x) + helper2(x);
}
......你把它分开了:
SRC /事/ PublicInterface.js
import {helper1} from './internal/helper1.js';
import {helper2} from './internal/helper2.js';
export function publicMethod1(x) {
return helper1(x);
}
export function publicMethod2(x) {
return helper1(x) + helper2(x);
}
SRC /事/内部/ helper1.js
export function helper1 (x) {
return 2 * x;
}
SRC /事/内部/ helper2.js
export function helper2 (x) {
return 3 * x;
}
这样,您可以轻松地测试helper1
和helper2
,而不使用Rewire和其他“魔法”(我发现,在调试时,或者当您尝试向TypeScript迈进时,不是提到新同事的可理解性较差)。它们位于一个名为internal
的子文件夹中,或类似的东西,将有助于避免在非预期的地方意外使用它们。
P.S。:“私人”方法的另一个常见问题是,如果你想测试publicMethod1
和publicMethod2
并嘲笑帮助者,你通常需要像Rewire那样做。但是,如果它们位于不同的文件中,您可以使用Proxyquire来执行此操作,与Rewire不同,它不需要对构建过程进行任何更改,易于阅读和调试,并且即使使用TypeScript也能正常工作。
要使私有方法可用于测试,我这样做:
const _myPrivateMethod: () => {};
const methods = {
myPublicMethod1: () => {},
myPublicMethod2: () => {},
}
if (process.env.NODE_ENV === 'test') {
methods._myPrivateMethod = _myPrivateMethod;
}
module.exports = methods;