有没有办法对定义在函数内部的 JavaScript 函数进行单元测试?

3

我想问一下,我能否在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 的值,然后重新定义它。这真的是你想要做的吗? - T.J. Crowder
@TJ 这是在动态语言中挂钩全局函数的标准方式。 - FryGuy
4个回答

2

在您的示例中,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。 - BeraCim

1

你可以这样做:

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

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

然后,对于newExternalFunction来说,运行单元测试相对简单。

0
理论上,你可以做这样的事情:
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实现。


0
你可以使用闭包来生成回调函数:
// 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:感谢您的回答。如果现在在// trying to unit test the stuff in here!...注释块的末尾,有一个对originalExternalFunction的调用,那么还能进行单元测试吗?更重要的是,是否可以在不修改现有代码的情况下对任何代码进行单元测试?谢谢。 - BeraCim
仔细研究函数闭包的工作方式,你将originalExternalFunction作为callback传入 - 这样你对原始函数的"调用"就可以与函数本身解耦。这样一来,你就可以轻松访问并测试其功能,因为它的功能不再与originalExternalFunction的功能绑定在一起。这只是一个快速的剪切和粘贴工作(只需删除对originalExternalFunction的调用)... 如果你想将函数的代码编辑到原问题中,我将能够给你展示一个更具体的例子。 - gnarf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接