【问题标题】:Jasmine.js: Race Conditions when using "runs"Jasmine.js:使用“运行”时的竞争条件
【发布时间】:2013-06-17 18:40:18
【问题描述】:

在使用 jasmine 测试我的代码时,我注意到一个奇怪的行为。与我的规范中的其他测试一起执行时,一个测试失败。当单独调用时,测试通过。

测试断言脚本 A.js 依赖于提供“创建”方法的脚本 B.js。我在测试中为“Create”创建了一个间谍并调用脚本 A.js (A.init),它将加载一些数据(loadData 再次返回一个 promise),然后调用“Create”方法 5 次(一旦 loadData -promise 已解决)。 A.init() 返回另一个承诺!

当我使用 Jasmine 的“runs”方法并等待 promise-init 解决时,我喜欢断言 B.Create 被调用了 5 次。

执行测试时,同一规范中的其他测试将为 B.Create 方法设置自己的间谍。所以我认为这会产生某种竞争条件。

注解:每个测试都会为 create-method (var createSpy = spyOn(B, "Create") 创建自己的 spy;

所以一切归结为以下问题:

  • 我是否面临竞争条件?
  • 如何防止这个问题?时间模拟 (jasmine.Clock.useMock) 不是真正的解决方案,因为我使用 promise-fake 模拟“loadData”方法。

更新 1: Richard Dingwall 在他的文章Parallel vs serial javascript async tests 中概述了 Jasmine 并行执行测试,所以这是我问题的根源吗?

Update-2 这是失败的测试:

/* more code */

crmRestKitCreateSpy = spyOn( CrmRestKit, 'Create' )
   .andCallFake( function ( entitySchemaName, obj ) {

       return {
           then: function ( callback ) {
               // fake a create response where the id attribute is populated
               callback( _.extend( {}, obj, { AccountId: cloneId } ) );
           }
       };
   } );

/* more code */

it( 'links all child-clones to the new parent-clone', function () {

// arrange - inject spy
spyOn( CrmRestKit, 'ByQueryAll' ).andReturn(
        alfa.fake.promise.buildFakeResolvePromise( { d: fakeChildAcccounts, __next: false }, 750 )
);

// arrange 
includedOneToManyRel = [accountToAccountRel];

// action 
var promise = alfa.util.clonemachine.deepClone( fakeId, includedOneToManyRel );

waitsFor( function () {
    return promise.state() === 'resolved';
}, 800 );


runs( function () {

    expect( crmRestKitCreateSpy.callCount ).toBe( 5 );

    // assert - all child-clones reference the new parent-clone
    expect( crmRestKitCreateSpy.calls[1].args[1].ParentAccountId.Id ).toBe( cloneId );
    expect( crmRestKitCreateSpy.calls[2].args[1].ParentAccountId.Id ).toBe( cloneId );
    expect( crmRestKitCreateSpy.calls[3].args[1].ParentAccountId.Id ).toBe( cloneId );
    expect( crmRestKitCreateSpy.calls[4].args[1].ParentAccountId.Id ).toBe( cloneId );
} );

});

Update-3 我认为我找到了我面临竞争条件的证据。以下测试通过。所以我的测试会受到其他正在运行的测试的影响。

it( 'its a trape', function () {

            waitsFor( function () {

                return ( crmRestKitCreateSpy.callCount > 0 );
            }, 4000 );

            runs( function () {

                expect( crmRestKitCreateSpy.callCount ).toBeGreaterThan( 0 );
            } );
        } );

【问题讨论】:

标签: javascript unit-testing jasmine race-condition


【解决方案1】:

好的,我似乎面临一个竞争条件:在使用“运行”时,多个测试都使用了 createSpy(请参阅问题中的 Update-3)。

原来茉莉花的时钟模拟解决了我的问题:

beforeEach( function () {

            // mock the ByQuery method
            crmRestKitByQuerySpy = spyOn( CrmRestKit, 'ByQuery' )
                .andCallFake( alfa.fake.promise.buildFakeResolvePromise( fakeChildAcccounts ) );

            // The Jasmine Mock Clock is available for a test suites that need the 
            // ability to use setTimeout or setInterval callbacks. It makes the 
            // timer callbacks synchronous, thus making them easier to test.
            jasmine.Clock.useMock();
        } );

it( 'it supports async execution - jasmine-timer-mock', function () {

            var deferedInMillisecond = 250;

            // arrange - inject the ByQueryAll method of the CrmRestKit
            spyOn( CrmRestKit, 'ByQueryAll' ).andReturn( alfa.fake.promise.buildFakeResolvePromise( {
                d: fakeChildAcccounts,
                __next: false
            }, deferedInMillisecond ) );

            // arrange 
            includedOneToManyRel = [accountToAccountRel];

            // action 
            var deepClonePromise = alfa.util.clonemachine.deepClone( fakeId, includedOneToManyRel );

            expect( deepClonePromise.state() === 'pending' );

            jasmine.Clock.tick( deferedInMillisecond + 1 );

            // assert - defere the assertion until the waitFor is completed
            expect( deepClonePromise.state() === 'resolved' );
        } );

【讨论】:

    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2019-02-10
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多