3

I would just like to ask whether I would be able to unit test the code inside ExternalFunction within the document.ready? I have tried many things for a while now and still couldn't work out how, and am at my wits end.

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

I'm unit testing using JsTestDriver. Test declaration is something like TestThisTest.prototype.test_this - function() {};

Thanks in advance.

2
  • Your code seems to be grabbing the value of ExternalFunction, and then redefining it. Is that really what you mean to be doing? Commented Dec 21, 2009 at 22:42
  • @TJ that's a standard way of hooking global functions in dynamic languages. Commented Dec 21, 2009 at 22:50

4 Answers 4

2

Since, in your example, ExternalFunction is not declared within the scope of the function, it is global (or at least, in whatever scope it may have been defined in outside ready). You can therefore test it by calling it as a global.

The trouble is, in order to assign the function to ExternalFunction, you have to run ready (which you could run manually, if you need). This means that if you put any other functionality in ready, then no, it is not unit testable. If your example code is an accurate reflection of reality, then I suppose it is kinda testable.

The point of a construct like this, is to hide the inner function. If you don't wish to hide it, then Anon.'s suggestion of defining newExternalFunction in a more accessible scope is what you need.

If your function needs to be a closure using variables from within ready, you could define newExternalFunction thus:

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

You would still need to ensure that ready has run, prior to unit testing, but you wouldn't have to rely on ExternalFunction not being reset to originalExternalFunction.

Sign up to request clarification or add additional context in comments.

1 Comment

@Paul: Thanks for your answer. ExternalFunction is actually an alias of a SharePoint function so I can't call it at will. I know I need to setup a dummy ExternalFunction before calling document.ready and have tried all the ways I could imagine, but nothing worked. I was thinking that kind of setup is similar to Java inner variables hence its very hard to test without being able to call the overriden ExternalFunction directly. I can't split ExternalFunction because at the last line of code in ExternalFunction, originalExternalFunction will get called with the then proper parameters.
1

You could do something like:

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

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

Then it's relatively straightforward to run your unit tests on newExternalFunction.

Comments

0

Theoretically, you could do something like:

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

That being said, I'm not sure exactly how to do that in javascript.

Comments

0

You could use a closure to generate your callback function:

// 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;
}

2 Comments

@gnarf: thanks for the answer. What if now in the // trying to unit test the stuff in here!... at the end of the comment block, there is a call to the originalExternalFunction? Is it still possible to unit test it? And more importantly, is it possible to unit test any of the code without modification of the existing code? Thanks.
Look closer into the way that function closure works, you pass in the originalExternalFunction as callback - that way your "call" to the original function can be decoupled from the function itself. You then have easy access to test its functionality, as its functionality is no longer tied to the functionality of the originalExternalFunction. It should be a quick cut and paste job (just remove your call to originalExternalFunction).. If you want to edit the code for the function into the original question, I'll be able to show you a more concrete example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.