【问题标题】:Testing TypeScript function which is not exported测试未导出的 TypeScript 函数
【发布时间】:2015-11-02 13:39:51
【问题描述】:

我使用 Mocha/Chai 来测试 JavaScript 前端代码,现在我们切换到 TypeScript。我有几个要测试的功能。但它们不应该是可出口的。我可以在不添加export 的情况下访问这些函数并对其进行测试吗?

【问题讨论】:

  • 我认为这是一般的编程观察;单元测试不应该专注于私有方法。如果您有某些公共方法的使用未涵盖的私有方法,那么只需摆脱它们即可。如果它们被使用公共方法覆盖,请使用这些公共方法。 (简单的观点,但就是这样)
  • 在切换到 TypeScript 之前你是如何处理这些问题的?
  • @Katana314 我想对非导出函数做一些基准测试。我怎样才能做到这一点?这与测试理念无关。
  • @Katana314 据我所知,这种观点有点过时了。有完全有效的用于测试内部方法的用例。多年来,我遇到了许多私有函数的例子,与它们的更高级别的公共接口相比,它们甚至允许进行更有意义的单元测试。单元测试的理想粒度并不总是必须与理想的公共接口相一致。另请注意,现代语言(例如 Rust)通常采用甚至鼓励私人测试的设计。

标签: javascript typescript mocha.js chai


【解决方案1】:

无法访问未导出的模块函数。

module MyModule {
    function privateFunction() {
        alert("privateFunction");
    }
}
MyModule.privateFunction(); // Generates a compiler error

但是,撇开私有​​方法测试的有效性问题不谈,您可以这样做。

将您的函数分组到一个实用程序类中,然后利用可以通过方括号表示法访问私有类成员这一事实。

module MyModule {
    export class UtilityClass {
        private privateFunction() {
            alert("privateFunction");
        }   
    }
}
var utility = new MyModule.UtilityClass();
//utility.privateFunction(); Generates a compiler error
utility["privateFunction"](); // Alerts "privateFunction"

【讨论】:

    【解决方案2】:

    虽然无法直接访问非导出函数,但仍有一种方法可以以“半隐藏”方式导出它们。一种可能的方法是:

    // In your library module declare internal functions as non-exported like normal.
    function someInternalFunctionA(x: number): number {
      return x;
    }
    
    function someInternalFunctionB(x: number): number {
      return x;
    }
    
    // At the bottom, offer a public escape hatch for accessing certain functions
    // you would like to be available for testing.
    export const _private = {
      someInternalFunctionA,
      someInternalFunctionB,
    };
    

    在测试方面你可以这样做:

    import { _private } from "./myModule";
    
    test("someInternalFunctionA", () => {
      expect(_private.someInternalFunctionA(42)).toEqual(42);
    });
    

    我喜欢这种方法的地方:

    • 无需将someInternalFunctionA直接标记为export
    • 应该很明显_private 下的内容并不是公共接口的正式组成部分。

    【讨论】:

    • 如果您正确地执行 TDD,则不应在生产环境中运行仅用于测试的代码。除了具有误导性之外,它还可能是潜在的问题来源。
    • @Teodoro 当然,这不是一个很好的解决方案,但从实用的角度来看:(1)导出私有符号的代码是一种非常小的形式“运行代码以在生产中进行测试”, (2) 这在我在现实生活中从事的项目中从来没有造成过麻烦,(3) 测试更细粒度的内部函数的可能性肯定有助于我们交付正确的代码。
    【解决方案3】:

    正如您在相关问题中看到的那样,在 StackOverflow 上对测试类或模块中的私有函数的问题进行了激烈的辩论 - 以下可能是甚至没有讨论的架构解决方案:

    如果这些功能觉得重要到可以单独测试,但不应作为模块的一部分访问,是否应该将它们放在自己的模块中?

    这将解决您的可访问性问题 - 它们现在是一个模块中的公共函数,您可以轻松地在另一个模块中使用它们,而不是将它们作为该模块的一部分公开。

    【讨论】:

      【解决方案4】:

      我找到的最佳解决方案是以不同的名称导出私有函数,这样这个名称会提醒您不要在其他任何地方使用此函数。

      export const getPriceTEST = getPrice;
      
      function getPrice(): number {
        return 10 + Math.Random() * 50;
      }
      
      

      【讨论】:

        【解决方案5】:

        但它们不应该是可导出的。我可以在不添加导出的情况下访问这些函数并对其进行测试吗?

        一般来说,不会。可以访问私有类成员,但不能访问模块的未导出成员。

        我会回应 @Katana314 的 cmets —— 单元测试不应该与非公共方法相关。尝试这样做表明您正在测试模块的实现细节,而不是模块声称要实现的合同。

        【讨论】:

        • 所以,如果我想测试它或用存根替换它,我必须导出函数。我说的对吗?
        • 争论是你不应该仅仅为了测试而导出一些东西。您正在对模块进行单元测试,以确保传入一组值会给您带来预期的结果,而不是模块内的内部处理流程。
        【解决方案6】:

        这是一个彻头彻尾的黑客攻击,但是嘿...

        window.testing = {};
        

        然后在你的模块中:

        module.exports = {
            myPublicFunction: myPublicFunction
        };
        
        window.testing.myModule = {
            myPublicFunction: myPublicFunction,
            myPrivateFunction: myPrivateFunction
        };
        

        【讨论】:

          猜你喜欢
          • 2011-07-06
          • 2019-07-08
          • 1970-01-01
          • 2018-04-03
          • 2013-02-28
          • 1970-01-01
          • 2019-03-29
          • 2021-04-02
          • 1970-01-01
          相关资源
          最近更新 更多