javascript - How to use a spy with toHaveBeenCalledWith and a mutable array in Jasmine.js? - Stack Overflow

I have some code which calls a callback function with an array as single argument. After calling the ca

I have some code which calls a callback function with an array as single argument. After calling the callback, the code changes the array contents. It is similar to this code:

function myCode( callback ) {
    var someArray = [ 1, 2, 3, 4 ];
    callback( someArray );

    // change someArray in arbitrary ways
    someArray.splice( 2 );
    ...
}

Now, I want to verify that the callback is called with the correct array content. Using Jasmine.js I would write my spec like this:

describe( "My code", function() {
    var callback;

    beforeEach( function() {
        callback = jasmine.createSpy( "My callback" );
        myCode( callback );
    });

    it( "calls the callback and passes the correct array", function() {
        expect( callback ).toHaveBeenCalledWith( [ 1, 2, 3, 4 ] );
    });
});

This fails. The problem is, that Jasmine.js records the array but does not make a copy of it. Since the array is changed after the call, the expect()-Line fails, even though the actual call fulfilled the expectation. The same problem occurs with mutable objects.

How can I test such code?

I have some code which calls a callback function with an array as single argument. After calling the callback, the code changes the array contents. It is similar to this code:

function myCode( callback ) {
    var someArray = [ 1, 2, 3, 4 ];
    callback( someArray );

    // change someArray in arbitrary ways
    someArray.splice( 2 );
    ...
}

Now, I want to verify that the callback is called with the correct array content. Using Jasmine.js I would write my spec like this:

describe( "My code", function() {
    var callback;

    beforeEach( function() {
        callback = jasmine.createSpy( "My callback" );
        myCode( callback );
    });

    it( "calls the callback and passes the correct array", function() {
        expect( callback ).toHaveBeenCalledWith( [ 1, 2, 3, 4 ] );
    });
});

This fails. The problem is, that Jasmine.js records the array but does not make a copy of it. Since the array is changed after the call, the expect()-Line fails, even though the actual call fulfilled the expectation. The same problem occurs with mutable objects.

How can I test such code?

Share Improve this question asked Oct 18, 2012 at 22:50 h2steinh2stein 6164 silver badges14 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

Jasmine does shallow copy the arguments passed on to the spy, which mean the arguments object will have reference to the same objects with which it has been called (in your case arguments will have the reference to someArray object only.

Jasmine code reference for spy implementation:

  spy = function() {
    callTracker.track({
      object: this,
      args: Array.prototype.slice.apply(arguments)
    });
    return spyStrategy.exec.apply(this, arguments);
  };

Deep copy of array (arguments) is not possible as a generic solution, problems are explained at link.

A solution to your problem could be writing your own callback and matcher for your specific use case, where you know what you have to copy (clone) exactly.

Sometimes if your unit tests are hard to get right, it's telling you the code needs to be more unit-y, and there's probably some method that has too many responsibilities. Looks like myCode is doing a couple different things: applying callback to some array, and then modifying that array. Perhaps the code that modifies the array can be extracted into its own method which myCode calls. Then you can simply stub out that extra method in the unit test which ensures that the callback is being called with the right arguments.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745078170a4609959.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信