【问题标题】:Is there anyway to unit test javascript functions defined within a function?无论如何对函数中定义的javascript函数进行单元测试?
【发布时间】:2009-12-21 22:39:11
【问题描述】:

我想问一下,我是否可以在 document.ready 中对 ExternalFunction 中的代码进行单元测试?一段时间以来,我尝试了很多东西,但仍然无法弄清楚如何做,我束手无策。

$(document).ready(function () {
    var originalExternalFunction = ExternalFunction;
    ExternalFunction = function(context, param) {
        // trying to unit test the stuff in here!
    }
}

我正在使用 JsTestDriver 进行单元测试。测试声明类似于 TestThisTest.prototype.test_this - function() {};

提前致谢。

【问题讨论】:

  • 你的代码好像是在抓取ExternalFunction的值,然后重新定义。这真的是你的意思吗?
  • @TJ 这是在动态语言中挂钩全局函数的标准方式。

标签: javascript jquery unit-testing


【解决方案1】:

由于在您的示例中,ExternalFunction 未在函数范围内声明,因此它是全局的(或至少在ready 外部定义的任何范围内)。因此,您可以通过将其称为全局来对其进行测试。

问题是,为了将函数分配给ExternalFunction,您必须运行ready(如果需要,您可以手动运行)。这意味着如果您将任何其他功能放在ready 中,那么不,它不是可单元测试的。如果您的示例代码准确地反映了现实,那么我想它是可测试的。

这样的结构的重点是隐藏内部功能。如果您不想隐藏它,那么 Anon. 建议在更易于访问的范围内定义 newExternalFunction 就是您所需要的。

如果您的函数需要使用 ready 中的变量作为闭包,您可以这样定义 newExternalFunction:

   var newExternalFunction;
    $(document).ready(function () {
        var originalExternalFunction = ExternalFunction;
        newExternalFunction = function(context, param) {
            // trying to unit test the stuff in here!
        }
        ExternalFunction = newExternalFunction;
    }

在单元测试之前,您仍然需要确保 ready 已运行,但您不必依赖 ExternalFunction 不会被重置为 originalExternalFunction

【讨论】:

  • @Paul:感谢您的回答。 ExternalFunction 实际上是 SharePoint 函数的别名,所以不能随意调用。我知道我需要在调用 document.ready 之前设置一个虚拟的 ExternalFunction 并尝试了我能想象的所有方法,但没有任何效果。我在想这种设置类似于 Java 内部变量,因此如果无法直接调用覆盖的 ExternalFunction 就很难测试。我无法拆分 ExternalFunction,因为在 ExternalFunction 的最后一行代码中,将使用适当的参数调用 originalExternalFunction。
【解决方案2】:

你可以这样做:

function newExternalFunction(context, param) {
    //etc.
}

$(document).ready(function () {
    var originalExternalFunction = ExternalFunction;
    ExternalFunction = newExternalFunction;
}

然后在newExternalFunction 上运行单元测试相对简单。

【讨论】:

    【解决方案3】:

    理论上,你可以这样做:

    ExternalFunction = function() { }
    ExecuteDocumentReady(); // implement a mock on $(document).ready(fn) to store the function, and then execute it here
    
    ExternalFunction(fakeContext, fakeParam);
    assert(fakeContext.foo == 12); // or whatever you need it to do
    

    话虽如此,我不确定如何在 javascript 中做到这一点。

    【讨论】:

      【解决方案4】:

      您可以使用闭包来生成回调函数:

      // create function to make your "extension" function
      function createHookFunction(callback) {
        // return a function 
        return function(context, param) {
           var ret;
           // // trying to unit test the stuff in here!
      
      
           if (typeof callback == 'function') {
             // if you want to trap the return value from callback, 
             // ret = callback.apply(...);
             callback.apply(this, arguments);
           }
           return ret;
        };
      }
      
      // your hook now becomes:
      $(document).ready(function() {
        ExternalFunction = createHookFunction(ExternalFunction);
      });
      
      // and your unit test becomes:
      var funcToTest = createHookFunction();
      funcToTest(testContext, testParam);
      
      // And, you could even test that the callback itself gets called
      
      function someTest() {
        var testContext = {}, testParam='test';
        var callbackCalled = false;
        var funcToTest = createHookFunction(function(context, param) {
          callbackCalled = (context === testContext) && (param === testParam);
        });
        return (funcToTest(testContext, testParam) == 'Expected Return') && callbackCalled;
      }
      

      【讨论】:

      • @gnarf:感谢您的回答。如果现在在 // 试图对这里的东西进行单元测试!... 在注释块的末尾,有一个对 originalExternalFunction 的调用怎么办?是否仍然可以对其进行单元测试?更重要的是,是否可以在不修改现有代码的情况下对任何代码进行单元测试?谢谢。
      • 仔细观察函数闭包的工作方式,将originalExternalFunction 作为callback 传递——这样你对原始函数的“调用”就可以与函数本身分离。然后,您可以轻松地测试它的功能,因为它的功能不再与originalExternalFunction 的功能绑定。这应该是一个快速的剪切和粘贴工作(只需删除您对originalExternalFunction 的调用)。如果您想将函数的代码编辑到原始问题中,我将能够向您展示一个更具体的示例。
      猜你喜欢
      • 1970-01-01
      • 2016-09-04
      • 1970-01-01
      • 1970-01-01
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      相关资源
      最近更新 更多