代码之家  ›  专栏  ›  技术社区  ›  swampsjohn

在javascript中测试私有函数

  •  16
  • swampsjohn  · 技术社区  · 15 年前

    我使用JavaScript中的模块模式将公共接口与私有实现分离。为了简化我正在做的事情,我的代码生成了一个图表。图表由多个部分组成(轴、标签、绘图、图例等)。我的代码如下:

    var Graph = function() {
      var private_data;
      function draw_legend() { ... }
      function draw_plot() { ... }
      function helper_func() { ... }
      ...
    
      return {
        add_data: function(data) {
          private_data = data;
        },
        draw: function() {
          draw_legend()
          draw_plot()
        }
      }
    }
    

    有些人主张只测试类的公共接口,这是有意义的,但我真的想参加一些测试,分别测试每个组件。如果我搞砸了draw_Legend()函数,我希望该测试失败,而不是对public draw()函数的测试。我走错了吗?

    我可以将不同类中的每个组件分开,例如创建一个Legend类。但是,为有时只有5-10行代码的代码创建一个类似乎很愚蠢,而且这会更糟糕,因为我需要在一堆私有状态中通过。我无法测试助手的功能。我应该这样做吗?我应该接受它并且只测试public draw()吗?或者有其他的解决办法吗?

    6 回复  |  直到 8 年前
        1
  •  9
  •   Helgi    15 年前

    无法从外部范围访问内部函数(private)。如果您想测试内部函数,可以考虑添加一个仅用于测试目的的公共方法。如果您使用某种类型的构建环境(例如Ant),则可以预处理用于生产的javascript文件并删除这些测试函数。

    实际上,JavaScript是一种面向对象的语言。它不是一个静态类型的。

        2
  •  5
  •   takacsot    12 年前

    我的解决方案只是一点小技巧。QUn单元示例:

    在qunit测试html的顶部,我声明:

    var TEST_AVAILABLE = true;
    

    在可测试类中,我有一个这样的片段:

    if(TEST_AVAILABLE){
       this.test={
          hasDraft:hasDraft,
          isInterpIdIn:isInterpIdIn,
          // other private methods
       };
    }
    

    在库尼特你可以核实

    test( "hello booth", function() {
      var b = new Booth();
      ok(b);
      ok(b.test);
      ok(!b.test.hasDraft());
    });
    
        3
  •  3
  •   Karlo Ibarra    12 年前

    我也有类似的问题。我提出的解决方案不是我喜欢的,但它确实能解决问题,而且我找不到更好的解决方案。

    function Graph()
    {
        this.Test = function _Test(expressionStr) { return eval(expressionStr); }
    
        var private_data;
        function draw_legend() { ... }
        function draw_plot() { ... }
        function helper_func() { ... }
        ...
    }
    

    测试:

    var g = new Graph();
    g.Test("helper_func()") == something;
    g.Test("private_data") == something2
    
        4
  •  1
  •   Sjeiti    12 年前

    其实有一个简单的方法。可以使用Ajax加载脚本并插入一个公开私有函数的函数。我有个例子 here 它使用qunit和jquery。但我相信使用纯JavaScript也可以很容易做到这一点。

        5
  •  0
  •   Chase Seibert    15 年前

    在面向对象的语言中,通常需要对 受保护的 方法通过让测试类从其测试的类继承。

    当然,javascript并不是一种面向对象的语言,而且这种模式不允许继承。

    我认为您要么需要公开您的方法,要么放弃对它们的单元测试。

        6
  •  0
  •   Michal Miky Jankovský    8 年前

    只有一个正确的选择: 用于测试和生产的不同版本

    1)仅标记开发部件

    /* test-code */
    api._foo = foo
    /* end-test-code */
    

    2)以后剥掉它们……;)

    grunt.registerTask("deploy", 
      [
        "concat",
        "strip-code",
        ...
    

    @菲尔沃顿写了很多漂亮的文章: