Javascript Jasmine.js:使用“时的种族条件”;“运行”;
在用jasmine测试代码时,我注意到一种奇怪的行为。在我的规范中,一个测试与其他测试一起执行时失败。单独调用时,测试通过 测试断言脚本A.js,该脚本依赖于提供“Create”方法的脚本B.js。我在测试内部为“create”创建一个spy,并调用脚本a.js(a.init),该脚本将加载一些数据(loadData再次返回一个承诺),然后调用“create”方法5次(一旦loadData承诺得到解决)。A.init()返回另一个承诺 当我使用Jasmine的“runs”方法并等待promise init被解析时,我喜欢断言B.Create被调用了5次 在执行测试时,同一规范中的其他一些测试将为B.Create方法设置自己的spy。所以我假设这会造成一些竞争条件 注释:每个测试都为create方法创建自己的spy(Javascript Jasmine.js:使用“时的种族条件”;“运行”;,javascript,unit-testing,jasmine,race-condition,Javascript,Unit Testing,Jasmine,Race Condition,在用jasmine测试代码时,我注意到一种奇怪的行为。在我的规范中,一个测试与其他测试一起执行时失败。单独调用时,测试通过 测试断言脚本A.js,该脚本依赖于提供“Create”方法的脚本B.js。我在测试内部为“create”创建一个spy,并调用脚本a.js(a.init),该脚本将加载一些数据(loadData再次返回一个承诺),然后调用“create”方法5次(一旦loadData承诺得到解决)。A.init()返回另一个承诺 当我使用Jasmine的“runs”方法并等待promise
var createSpy=spyOn(B,“create”
)
因此,所有问题归结为以下问题:
- 我是否面临比赛条件
- 我如何防止这个问题?时间模拟(jasmine.Clock.useMock)不是一个真正的解决方案,因为我用一个假承诺来模拟“loadData”方法
/* 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 );
} );
})
更新-3
我想a找到了我面临比赛条件的证据。以下测试通过。因此,我的测试会受到其他正在运行的测试的影响
it( 'its a trape', function () {
waitsFor( function () {
return ( crmRestKitCreateSpy.callCount > 0 );
}, 4000 );
runs( function () {
expect( crmRestKitCreateSpy.callCount ).toBeGreaterThan( 0 );
} );
} );
好的,看起来我面临一个竞争条件: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' );
} );
拜托,这有点难理解。你能发布一个简单版本的规范是如何设置的吗?