Posts about mocks

BDD Style Mocks in Javascript

I was tasked with researching Javascript testing in the browser. Saw this video, whose message is simple: decouple your code to be more testable. This is a testing 1.0 concept put in the context of Javascript/Ajax. So I set out to try out their methodology. I wrote a piece of code to do live updating in respond to keypresses in a field. It started out very ad-hoc so I refactored it to be an object:
function LiveUpdater(inputField, resultElement, url){
    this.inputField = inputField;
    this.url = url;
    this.lastValue = null;
    this.resultElement = resultElement;
    var self = this;
    this.pe = new PeriodicalExecuter(function(){
        if (self.lastValue != self.inputField.value){
            self.lastValue = self.inputField.value
            new Ajax.Updater(self.resultElement, self.url, {
              method: 'get',
              parameters: { query: self.inputField.value }
            });
        }
    }, 0.5);


But this still isn't testable. To follow their methodology, I would have to break this up into 3 objects: the view, the controller, and the data source. I started out on that path - using jsMock(those guys used a home grown mock library) - but it soon became apparent that my little chunk of managable code would have to more than double in size just to be testable, it was to heavy for my taste.

But it doesn't have to be this way. jsMock has the limitation that you cannot mock only certain methods on an object, it's basically all or nothing. Therefore, if you want to test the expectation or stub out a method, you must refactor it out as an object on its own. I've long gotten used to rspec and it doesn't have this limitation. It turns out it's not hard to fix this for jsMock, it's a small library - merely 300 some lines of code - and I was able to add this ability and give it a more rspec style of writing stubs and expectations. Long story short, here's my new code:
function LiveUpdater(inputField, resultElement, queryParameterKey, url){
    this.lastValue = null;
    var self = this;
    this.getParams = function(){
        var params = {}
        params[queryParameterKey] = inputField.value
        return params
    }
    this.update = function(){
        new Ajax.Updater(resultElement, url, {
          method: 'get',
          parameters: self.getParams()
        });       
    }
    this.check = function(){
        if (self.lastValue != inputField.value){
            self.lastValue = inputField.value
            self.update();
        }
    }
    this.start = function(){
        new PeriodicalExecuter(self.check, 0.5);
    }
}


And my tests(using Thomas Fuchs' unittest framework, although you could also use jsUnit):
new Test.Unit.Runner({
setup: function() {
    JSMock.extend(this)
    myField = {value:"hello"}
    this.lu = this.makeMockable(new LiveUpdater(myField, document.createElement('div'), 'query', ''))
},

teardown: function() {
    this.verifyMocks()
},

testCheckShouldUpdateInitially: function() { with(this) {
    lu.shouldReceive('update').with_no_args()
    lu.check()
}},

testCheckShouldNotUpdateWhenNothingHasChangedTheSecondTime: function() { with(this) {
    lu.stub('update').andReturn(null)
    lu.check()
    lu.shouldNotReceive('update').with_no_args()
    lu.check() 
}},

testParamsShouldBeRight: function() { with(this) {
    assert(mapEqu({query:'hello'}, lu.getParams()))
}}
 
}, {testLog: "testlog"});


As you can see I refactored the activity into 4 methods. Only 2 of them are tested: check() and getParams(), there other 2 are basically direct third party library calls.

To show off some other things you can do:
function Robot(){
    var self = this
    this.move = function(){
        if (self.facingWall())
            self.turnToTheLeft()
        else
            self.goStraight()
    }
    this.goStraight = function(){
       
    }
    this.facingWall = function(){
    }
    this.turnToTheLeft = function(){
    }
}

...
testShouldTurnToTheLeftWhenFacingWall: function() { with(this) {
    robot.stub('facingWall').andReturn(true)
    robot.shouldReceive('turnToTheLeft').with_no_args()
    robot.move()       
}},
testShouldNotGoStraightWhenFacingWall: function() { with(this) {
    robot.stub('facingWall').andReturn(true)
    robot.shouldNotReceive('goStraight').with_no_args()
    robot.move()
}},
...
function Boxer(){
    var self = this
    this.health = 10
    this.hit = function(opponent, power){
        opponent.hurt(power)
    }
    this.hurt = function(points){
        self.health -= points
    }
}
...
testGettingHitShouldHurtOpponentBySameAmountAsPower2: function(){ with(this){
    boxer.shouldReceive('hurt').with(5)
    new Boxer().hit(boxer, 5)
}},


Here's a zip file for the code: jsMockB.zip. I may put it up on svn somewhere later.
Posted by airportyh 9 months ago about javascript, mocks, programming and testing (0 comments)

Mock Testing and stub everything

This is a follow up to Advantures in Testing with Mocks. I have been growing dissatisfied with the mockist style of testing recently. The reason is, I was trying to learn it, but it just required me to stub out everything that was called. Not only was it tedious, it also cause the test code to be way too dependent on the implementation code. It got to the point where to write a test, I first have to look at the implementation to see what are the methods that are called. I was all but ready to call it quits on the mockist style.

But, yesterday I found stub_everything, which allowed me to find a way to embrace mocks once again. Basically, stub_everything('my object') is used in place of mock('my object'), which gives you a mock object that will return nil for any message sent to it that it doesn't understand without bombing out. This means that I can escape specifying every method call that has to go on during the tested method invocation.

Also, I realized that mocks are not to be used in all situations, but should rather be used strategically in certain spots. Basically, you want to avoid having your tests be dependent on your code. To give an example, let's say you want to test a controller method that looks up a user from a user ID. Naturally, you would stub out User.find, right? But what if the implementation used User.find_by_id instead? The problem is that there's more than one way to do this, and therefore the implementation is too maliable. Therefore, if it were me, I would not use a mock for a situation like this. Mocks and stubs are to be used only for cases where the method call - or message - is stable, there's only one method available to accomplish the given task, and when theh message is meaningful. For all messages that are not meaningful to be tested for the particular behavior, use stub_everything to ignore them. Here's an example:
describe "audit" do
  controller_name :project
  before :each do
    setup_projects # load data into db
    @user = stub_everything('user')
  end
   
  it "should audit when user is logged in" do
    controller.stub!(:current_user).and_return(@user)
    @user.should_receive(:audit).once
    get :show, {:id => @project.id}, {:user => 1}
  end
end
Here, I justify stubing out the controller's current_user method because that's the only way to get at the current_user that the authentication system provides. As for the expectation for audit, it's also a stable and non-aliased method. But even more importantly, that's exactly what I want to test! This is a case when I want to test the fact that the :audit method was called more so than I want to test its outcome as encoded in the database, because as I change the implementation of audit, its database representation could very well change, heck, audit info might not even be store in the database. As for the rest of the data - how project is looked up - that's retrieved from the database like normal. Real mockist testing people would say that db accesses are slow. There's a point to be made that project look up can also use a stub_everything, but one drawback of that is if the implementation does a multi-level object traversal like: project.name.length, then returning nil for name won't work, and you have to write some extra mocking code. Hmm, perhaps what is needed is a really_stub_everything which instead of returning nils for everything, returns itself instead, then you can really ignore all interactions with this object. Hmm..., that's a thought.

And so, I think that from now on, my mock testing approach - which is not really the mockist way - is to still use fixtures or other db setup templates by default, but only use mocks at select places where it makes sense.
Posted by airportyh about 1 year ago about mocks, programming, ruby and testing (0 comments)