如何在javascript全局命名空间中存根/模拟一个函数

时间:2010-12-20 01:51:07

标签: javascript testing mocking

我正在尝试在测试期间存根/模拟/覆盖函数调用,这会将日志写入数据库。

function logit(msg) {
  writeMessageToDb(msg);
}

function tryingToTestThisFunction(){
  var error = processSomething();
  if (error) {
    logit(error);
  }
}

我希望logit()在测试期间简单地打印到控制台...并且在isTesting()函数中执行“logit()”if / else块不是一个选项。

这可能不包括一些额外的模拟框架。我目前正在使用JsTestDriver进行单元测试,并且没有机会评估任何模拟框架。目前理想的解决方案是在没有其他框架的情况下处理这个问题。

6 个答案:

答案 0 :(得分:7)

我使用Jasmine和Sinon.js(使用Coffeescript),这是我如何将confirm()方法存根,例如,只返回true。

beforeEach ->
  @confirmStub = sinon.stub(window, 'confirm')
  @confirmStub.returns(true)

afterEach ->
  @confirmStub.restore()

答案 1 :(得分:3)

在javascript中,最新的定义是流行的。

所以只需在第一个定义之后重新定义logit方法。

function logit(msg) {
  console.log(msg);
}

示例:http://www.jsfiddle.net/gaby/UeeQZ/

答案 2 :(得分:1)

你可以覆盖窗口对象上的方法吗?在Chrome控制台中,这可以正常工作

function test() {console.log('test')};
window.test();

答案 3 :(得分:1)

只需覆盖logit函数,这可以在logit定义之后的任何时间调用。

(function(){
  //keep handle to original logit method.
  var ol = logit;

  //shorter lookup path for slice
  var s = Array.prototype.slice;

  //logit override
  logit = function() {
    //if in testing
    if (typeof IsTesting == "function" && !!IsTesting()) {
      //log the arguments
      console.log.apply(console, s.call(arguments));
    } else {
      //otherwise, call the original function.
      ol.apply(this, s.call(arguments))
    }
  }
}());

答案 4 :(得分:1)

我一直在研究完全相同的问题。开发人员给了我一个HTML5应用程序来测试,所以我当然不能改变他们的代码进行测试。我决定使用qunitsinon以及sinon-qunit。

对于像我这样的新手到JavaScript单元测试,我对网络上的sinon文档和各种示例感到疯狂,因为大部分内容似乎都是未提及的隐含环境。下面的代码是一个完整的页面,所以我希望不会有任何混淆。

我必须调用的函数是caller(),我无法对stubme()做任何事情,因为它在开发人员的代码中。但是,我可以在我的测试代码中添加sinonstub()。但是如何让它与sinon一起工作? sinon文档确实让我困惑了一段时间,但下面是简单的解决方案。 stub4stubme对象可用于控制存根操作,还可以获取存根调用发生的信息。

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <link rel="stylesheet" href="qunit-1.12.0.css" type="text/css" media="screen" />
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
    <script src="sinon-1.7.3.js"></script>
    <script src="qunit-1.12.0.js"></script>
    <script src="sinon-qunit-0.8.0.js"></script>
    <script>

        // Dev code in another file
        function stubme() {
            return "stubme";
        }

        function caller() {
            return "caller " + stubme();
        }
        // End of dev code

        var sinonstub = function () {
            return "u haz bin stubbed";
        };

        test("Stubbing global environments", function () {
            equal(caller(), "caller stubme");

            var stub4stubme = this.stub(window, "stubme", sinonstub);

            equal(caller(), "caller u haz bin stubbed");
            ok(stubme.called);
        });

    </script>
</body>
</html>

答案 5 :(得分:0)

因为在Javascript中不仅链接了运行时,而且最后一个单词获胜已链接,只需使用您在测试中所需的行为重新声明该方法:

function yourTest(){
    oldImpl = logit;   // better to use a setup.
    logit = function(msg){ Console.log.apply(console, s.call(arguments));};
    // do you assertions: assert.... yada.

    logit = oldImpl;  // Do this to keep your test isolated from the others you'll be executing in this test run. Better to use a tear down.
}
相关问题