开发者

How can I stub/mock a function in the javascript global namespace

I'm trying to stub/mock/override a function call during testing which writes a log to a DB.

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

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

I'd like logit()开发者_如何学编程 to simply print to the console during testing...and doing a "isTesting()" if/else block inside the logit() function is not an option.

Is this possible without including some additional mocking framework. I'm currently using JsTestDriver for unit testing and have not had a chance to evaluate any mocking frameworks. An ideal solution at the moment would be to handle this without another framework.


I use Jasmine and Sinon.js (using Coffeescript), here's how I stub out the confirm() method to, for example, just return true.

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

afterEach ->
  @confirmStub.restore()


In javascript the latest definition is the prevalent.

so just redefine the logit method after the first definition.

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

example : http://www.jsfiddle.net/gaby/UeeQZ/


I have been working on exactly the same problem. The developers gave me an HTML5 app to test, so of course I can't change their code for testing. I decided to use qunit and sinon, along with sinon-qunit.

For a newb to JavaScript unit testing like me, I was going nuts with the sinon documentation and various examples on the web, as most of it seems for an implied environment that isn't mentioned. The code below is a complete page, so I hope nothing is left for confusion.

The function that I have to call is caller() and I can't do anything about stubme() because it's in the developer's code. However, I can add sinonstub() in my test code. But how to get it to work with sinon? The sinon documentation really confused me for a while, but below is the simple solution. The stub4stubme object can be used to control the stub action, and also get the information about what's happening with the stub calls.

<!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>


Javascript is not only runtime linked, but is the last word wins linked as well. This means you can redeclare the method with the behavior you want in your test (since your test has the last word):

function yourTest(){
    oldImpl = logit;   // An even better approach is to do this in 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. An even better approach is to do this in a teardown.
}


can you just override the method on the window object? In Chrome console this works

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


just override the logit function, this can be called anytime later than logit is defined.

(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))
    }
  }
}());
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜