Jasmine.js:使用“运行”时的竞争条件 [英] Jasmine.js: Race Conditions when using "runs"

查看:142
本文介绍了Jasmine.js:使用“运行”时的竞争条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have noticed a strange behaviour when testing my code with jasmine. One test fails when executed together with the other tests in my spec. When called alone the test passes.

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

The test asserts the script A.js that depends on script B.js which offers the method "Create". I create inside the test a spy for the "Create" and invoke script A.js (A.init) that will load some data (loadData with returns again a promise) and then call the "Create" method 5 times (once the loadData-promise is resolved). The A.init() returns another promise!

当我使用Jasmine的runs方法并等到promise-init被解析时,我想断言B.Create被调用了5次。

When I use the "runs" method of Jasmine and wait until the promise-init is resolved, I like to assert that B.Create was called 5 times.

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

When executing the test some other test in the same spec will set up its own spy for the B.Create method. So I assume this will create some-how a race-condition.

注释:每个测试都为create-method创建自己的间谍( var createSpy = spyOn(B,Create);

Annotation: Each test creates its own spy for the create-method (var createSpy = spyOn(B, "Create");

所有归结为以下问题:


  • 我是否面临竞争条件?

  • 如何防止此问题?时间模拟(jasmine.Clock.useMock)不是真正的解决方案,因为我模拟了loadData方法承诺是假的。

Update-1
Richard Dingwall在他的文章中概述< Jasmine执行的href =http://richarddingwall.name/2012/04/28/parallel-vs-serial-javascript-async-tests/\"rel =nofollow>并行与串行javascript异步测试并行测试,这是我问题的根源吗?

Update-1: Richard Dingwall outlines in his article Parallel vs serial javascript async tests that Jasmine executes the tests in parallel, so is this the root of my problem?

Update-2
这是失败的测试:

Update-2 This is the test that fails:

/* 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
我认为发现了我面临竞争条件的证据。以下测试通过。所以我的测试受到其他正在运行的测试的影响。

Update-3 I think a found the proof that I am facing a race-condition. The following test passes. So my test is affected by other running tests.

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

            waitsFor( function () {

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

            runs( function () {

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


推荐答案

好吧,好像我正面临着竞争条件:使用运行时,createSpy由多个测试使用(请参阅问题中的Update-3)。

Ok, seems like I am facing a race-condition: The createSpy is used by multiple tests when using "runs" (see Update-3 in the question).

事实证明,Jasmine的Clock-Mock解决了我的问题:

In turns out that the Clock-Mock of Jasmine solved my problem:

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' );
        } );

这篇关于Jasmine.js:使用“运行”时的竞争条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆