Monday, August 11th, 2008

MockMe: A new JavaScript mocking framework

Category: JavaScript, Testing

Johannes Link is an Agile fellow who wasn’t 100% happy with the existing JavaScript unit test frameworks, and he explained why. He gives an example:

javascript

  1. testDoubleSpeaker: function() { with(this) {
  2.     var actualMsg = null;
  3.     var mockSay = function(msg) {
  4.       actualMsg = msg;
  5.     };
  6.     Speaker.say = mockSay;
  7.     DoubleSpeaker.say('oops');
  8.     assertEqual('oopsoops', actualMsg);
  9.   }}

It works, but he discusses how this changes the global world, which is a bad thing. Would it be nicer to spy and end up with:

javascript

  1. testDoubleSpeaker: function() { with(this) {
  2.     mock(Speaker).andDo(function() {
  3.         DoubleSpeaker.say('oops');
  4.         verify(Speaker.say)('oopsoops');
  5.     });
  6.   }},

This is an example from his new framework, MockMe, which has the main features:

  • The basic granularity of mocking should be the function. If I want to, I can fake the behaviour of a single function without influencing the rest (of an object or a prototype or the global namespace or whatever).
  • Most of the time, spying is a better idea than mocking because it’s simpler. Spying basically means that, instead of specifying the expected interaction with your mock spy object before doing the test, you use the mock spy object to spy into the interaction as it happens and verify that afterwards. In that respect I borrowed heavily from mockito, a spying framework that’s gaining more and more attention in the Java world.

A few other examples:

javascript

  1. when(f)('in').thenReturn('out');
  2. assertEqual('out', f('in'));
  3.  
  4. when(f)({name: 'hello'}).thenReturn('yeah');
  5. assertEqual('yeah', f({name: 'hello'}));
  6.  
  7. when(f)(any()).thenReturn('yeah');
  8. assertEqual('yeah', f(1));
  9.  
  10. verify(times(2), f)(1); //succeeds
  11. useMockerFor(function(mocker)) {
  12.     mocker.within(MyObject).mock('f1');
  13.     when(MyObject.f1)().thenReturn(5);
  14.     assertEqual(7, MyObject.f2());
  15. } // Here everything you mocked will automatically be restored
  16.  
  17. assertEqual(3, MyObject.f2());

Posted by Dion Almaer at 8:22 am
7 Comments

+++--
3.4 rating from 20 votes

7 Comments »

Comments feed TrackBack URI

I dig this. Looks cool.

I really wish there were more books on testing with JavaScript, Ruby, and Python. There are many great tools, take Ruby for example… Flexmock, Mocha, Rspec, etc… would love to see a book that really delved deep into best strategies and techniques for using them. Same goes for JS, which seems to be behind the curve with TDD practices.

Comment by holts — August 11, 2008

This looks better,just like IVR I use frequently.

Comment by jmneter — August 12, 2008

You’re not the only one holts, I think this is an area where the JavaScript community often falls well short of the mark. I’ve been trying to get some dialog on the subject going over at the AltDotJS Google Group. We’re trying to put together a place where developers can discuss TDD/BDD, design patterns, agile, DSL’s all within the context of JavaScript. So anyone who is interested in these subjects and others which don’t get much air time at present please join the group and contribute.

It seems like there’s a run of testing tools being released for JavaScript at the moment. If you follow the link above there are details about two new JavaScript mocking frameworks (Amok and Smoke) and one new BDD testing framework (Screw Unit).

Comment by ChrisInCambo — August 12, 2008

The biggest difference between Amok & Smoke on one side and MockMe on the other is that MockMe is a *spy* and not a *mock* framework. This leads to a different style of testing since – most of the time – you can be less specific in your tests with regards to your expected behaviour; this means that your tests will fail less often during refactoring.
Apart from that all three seem similar fit for doing their job.

Comment by jlink — August 12, 2008

The spying technique is something I’ve read about but never used, but now we have framework so I can’t wait to give it a try next time I start a project.

@jlink: At first glance would I be wrong in saying that spying puts more emphasis on verification of what occurred during the life cycle of the spy rather than simply implementing an interface?
For me overuse of post use mock verification is in itself a testing smell as it is a way of verifying the indirect outputs of the system under test and therefore requires a knowledge of the internal workings of the class which depends on the mock/stub and moves us further away from ‘black box’ testing.

Comment by ChrisInCambo — August 12, 2008

@ChrisInCambo:
IMO both spying and setting up mock expectations couples you to the implementation to some degree since collaboration (asking other objects to fullfill tasks for me can be considered an implementation detail). The trick is to do that only as much as needed.
That said, spying looks like less coupling to me (compared to mock expectations) because by default you only specify what you absolutely want to happen, whereas most mocking frameworks expect you to specify all calls by default.
Probably it’s a matter of taste. I changed from one style (expectations) to the other (after the fact verifications) after 7 years. It just feels more natural…

Comment by jlink — August 14, 2008

Spies and mock expectations do couple you to how input / output collaborators are intended to be in use by a particular object. However, only doing “after the fact” state based verification requires that you have a test environment setup with all of the necessary object dependencies in place, and their dependencies in place. This is also coupling your test to implementation. Testing an object in isolation makes the object implementation clean as well as the the test.

Often times when you only do pure black-box testing the tests themselves can be difficult to understand and change because there is so much going on just to set up the testing environment.

Mocks are also a great design tool to discover interfaces you want to work with before it may exist. I think it’s more than a matter of taste. I think it’s understanding the value provided by which technique in a given situation, and choosing the appropriate one.

Comment by zdennis — October 16, 2008

Leave a comment

You must be logged in to post a comment.