cleishm / jsmockito

Javascript mocking framework inspired by the awesome mockito
http://jsmockito.org
Other
106 stars 19 forks source link

Feature Request: Add the ability to reset the recorded interactions, for use with verifyNoMoreInteractions() #10

Open gregjacobs opened 12 years ago

gregjacobs commented 12 years ago

It would be very useful to have a method which resets the interactions that have been recorded on a mock object, so that verifyNoMoreInteractions() can be used more effectively.

Consider the following scenario:

function MyClass( dependentObj ) {
    this.dependentObj = dependentObj;

    // Subscribe to some event on dependentObj
    dependentObj.addListener( 'myevent', function(){} );
}

MyClass.prototype.myMethod = function() {
    this.dependentObj.setSomething();
}

If I want to test myMethod() to see that dependentObj.setSomething() is called, my test may look something like this:

var mockDependentObj = mock( DependentObjClass );
var instance = new MyClass( mockDependentObj );

// Call the method to test, and verify
instance.myMethod();
verify( mockDependentObj ).setSomething();     // good...
verifyNoMoreInteractions( mockDependentObj );  // error! it got a call to 'addListener()' in the constructor

So what I propose is some way to reset the interactions that have been recorded on the mock. We could reset the interactions that the mock has recorded immediately after the MyClass instance has been created, so that we don't worry about what happened in the constructor. Ex:

var mockDependentObj = mock( DependentObjClass );
var instance = new MyClass( mockDependentObj );

// Reset interactions on the mockDependentObj which were performed in the MyClass constructor
resetInteractions( mockDependentObj );

// Call the method to test, and verify
instance.myMethod();
verify( mockDependentObj ).setSomething();     // good
verifyNoMoreInteractions( mockDependentObj );  // good
cleishm commented 12 years ago

I'm very hesitant to add anything that encourages the use of verifyNoMoreInteractions - it tends to encourage poor test practices. You can read a good blog about this here:

http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/

Have you tried using never? That tends to be a better idea.

You can also read a good discussion of this for Mockito here: http://groups.google.com/group/mockito/browse_thread/thread/fefc46df7b65ce5f/bbe36216cddb2ce3#bbe36216cddb2ce3

All that said, I'll think about adding something of this sort. Patches are also appreciated.

ghost commented 12 years ago

How about, instead of resetting the recorded interactions to be able to create snapshots, from where then recorded interactions would start anew? That way, the history of the interactions would not be lost but rather kept in a backlog of recorded interaction snapshots.

cleishm commented 12 years ago

This amounts to much the same thing, and is only necessary because of the use of verifyNoMoreInteractions.

I'm suggesting that verifyNoMoreInteractions is often not necessary, as the article and forum I referenced discuss. That said, there are some situations that could find both being useful - so I'll consider adding a reset.

gregjacobs commented 12 years ago

I would personally say that the use of verifyNoMoreInteractions() is definitely situational. I don't often use it myself, but I have found a few cases where I do want to use it.

The one I came across when posting the issue was for a method that called other methods. I pretty much wanted to make sure that a certain dependency wasn't mutated (i.e. didn't get any more "tell" operations performed on it) than I expected.

I liked that article btw, and the distinction that he made about "ask" and "tell" operations.