0
\$\begingroup\$

Given a production module like this:

function ($) {
   var 
    showForm = function () {
        $.get(url, function (html) {          
            $('body').append(html);
        });
    };

   return {
       showForm: showForm
   };
});

I have written the following unit test:

it("calling showForm appends html to existing page", function () {

    var testPage = $('<div><body><span></span></body></div>');
    var expectedPage = $('<div><body><span></span><label></label></body></div>');
    var htmlToAppend = $('<label></label>');

    var callback = function () { return testPage.append(htmlToAppend); }


    sinon.stub(presenter, "showForm").yields(testPage); 

    presenter.showForm(callback);

    expect(testPage.html()).to.equal(expectedPage.html());
});

I am trying to test that when presenter.showForm is called, the returned html is appended successfully appended. Problem is, I'm not usre if it's a valid test as pretty much everything is fake.

I'm toying with the idea of abstracting out the call to $('body').append(html); to another public function of the module or perhaps even to another module so that the call presenter.showForm(callback); can use the real function but I'm not sure?

I hope that all makes sense.

Can someone review and advise please?

\$\endgroup\$
  • 1
    \$\begingroup\$ First write a failing test. Then make it pass by writing non-test code only. Then you should be sure you haven't faked everything. \$\endgroup\$ – abuzittin gillifirca Jul 19 '13 at 11:22
1
\$\begingroup\$

I'm not quite sure what you mean by "abstracting out the call...", but given that the "production module" actually looks like that, then I'd say that you have a perfectly valid little test there.

It is good to hear that you really are interested in making sure that your test cases are testing the right things. Unit tests are too often something that programmers write simply because they are forced to do it, and they are therefore happy enough when the tests don't fail - not pausing to consider that it might have passed because the test was incorrect, tested the wrong criteria, or did not in fact test anything at all.

Using fake data is what you normally do at this level of functionality, so you are good there. You might generally want to consider using more than one set of test data, but in this case I would say that it is not necessary.

\$\endgroup\$
  • \$\begingroup\$ Oh, and by the way: Good advice from @abuzittin in the comment to your post. Do make sure that your tests actually fails when the result is not the expected. For example by adding some character to htmlToAppend without making the corresponding change to expectedPage. \$\endgroup\$ – Boise Jul 19 '13 at 23:49
  • \$\begingroup\$ This did answer my question, so is the accepted one. However, I decided to go down a slightly different route, which I've posted in case it's helpful to others. \$\endgroup\$ – davy Jul 23 '13 at 8:48
0
\$\begingroup\$

I decided to add a callback to showForm so that I could get the returned html from the inner ajax request like so:

 var showForm = function (url, callback) {         
       $.get(url, function (html) {
           $('body').append(html);

           if (callback != undefined)
               callback(html);
       });           
 };

The test now looks like this:

 it("showForm calls jQuery.append", function (done) {

     // 1
     $.mockjax({                                             
          url: '/fake',
          dataType: 'html',
          responseText: '<label></label>'
     });             

     // 2
     var spy = sinon.spy($.fn, "append");                   

     // 3
     presenter.showForm('/fake', function (html) {
         done();
         expect(spy.withArgs('<label></label>').calledOnce).to.be.equal(true);    
     });
 });
  1. I used the jQuery.mockjax.js library to setup a fake call and return fake html
    from the ajax request.

  2. I then setup a spy on jQuery's append function.

  3. I can then check the spy was called with the html that would be returned from the ajax request. (my thinking is that I don't need to test that jQuery actually append the
    data, just that the call was made).

This technique gives me more comfort that I am appending the html returned from my ajax request to the form. I would be even more happy if I could test that the body is being used as the selector but that's another story...

Hope this is helpful.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.