如何对未导出的函数进行单元测试?

How can I unit test non-exported functions?

在 JavaScript ES6 模块中,可能有许多小的、易于测试的函数应该被测试,但不应该被导出。如何在不导出模块的情况下测试模块中的函数? (不使用 Rewire)。

导出“exportedForTesting”常量

function shouldntBeExportedFn(){
  // Does stuff that needs to be tested
  // but is not for use outside of this package
}

export function exportedFn(){
  // A function that should be called
  // from code outside of this package and
  // uses other functions in this package
}

export const exportedForTesting = {
  shouldntBeExportedFn
}

以下可用于生产代码:

import { exportedFn } from './myPackage';

这可以用于单元测试:

import { exportedFn, exportedForTesting } from './myPackage';
const { shouldntBeExportedFn } = exportedForTesting;

此策略为我团队中的其他开发人员保留了上下文线索,即 shouldntBeExportedFn() 除了测试外不应在包外使用。

我已经使用它很多年了,我发现它非常有效。

乔丹,我希望我能为你提供更好的答案。我过去在 JavaScript 和 C# 上下文中都有非常相似的问题...

回答/不回答

在某些时候我不得不接受这样一个事实,即如果我想要涵盖 unexported/private functions/methods 的粒度单元测试,我真的应该公开它们。有人会说这是违反封装的,但也有人不同意。前一组人也会说,直到一个函数exported/public,它本质上是一个实现细节,因此不应该进行单元测试。

如果您正在练习 TDD then Mark Seeman's explanation should be relevant (Pluralsight),希望它能阐明为什么可以公开内容。

我不知道您是否可以找到一些技巧来直接从您的单元测试中调用未导出的函数而不更改被测代码,但我个人不会那样做。

只是一个选择

另一种选择是将您的图书馆一分为二。比如说,库 A 是您的应用程序代码,而库 B 是包含您希望避免从 A 的界面导出的所有函数的包。

如果它们是两个不同的库,您可以在非常精细的级别上控制公开的内容和测试方式。库 A 将仅依赖于 B 而不会泄露 B 的任何细节。 AB 都可以独立测试。

当然,这将需要不同的代码组织,但它会起作用。 Lerna 等工具简化了 JavaScript 代码的多包存储库。

旁注

,老实说。通过测试使用它的函数来测试非导出函数并不是真正的单元测试。

也许是 necro-posting 但我解决这个问题的方法是使用 'index.js' 只导出你想要制作的函数 public.

你仍然需要导出私有函数,但这种方式确实在测试和生产之间增加了一个抽象层。

module/startingFile.js

function privateFunction1() {/**/};
function privateFunction2() {/**/};

// Different syntax is a good visual indicator that this is different to public function
exports.privateFunction1 = privateFunction1;
exports.privateFunction2 = privateFunction2;

exports.publicFunction1 = function() {/**/};
exports.publicFunction2 = function() {/**/};

module/index.js

exports.publicFunction1 = require('./startingFile.js').publicFunction1;
exports.publicFunction2 = require('./startingFile.js').publicFunction2;

ImportingFile.js

const { publicFunction1, publicFunction2 } = require('./module');

您甚至可以使用 NODE_ENV 变量仅在不在生产环境中时导出私有函数。