使用 Jasmine 进行异步测试

Posted

技术标签:

【中文标题】使用 Jasmine 进行异步测试【英文标题】:Async test with Jasmine 【发布时间】:2013-06-28 02:33:07 【问题描述】:

我正在尝试对 Jasmine 和 RequireJS 进行一些测试。一切都很顺利,直到我注意到我所描述的函数的上下文存在问题。

我正在做一些 Ajax 测试,所以我要做的第一件事是设置成功的侦听器,然后请求该服务。然后,在我的每个 it() 声明中,我根据服务响应进行测试。

这是我的spec modules:

// auth.js
define(['service/auth'], function(auth) 
  describe('Tests "auth" service', function() 
    var data;
    var OPTIONS = 
      CN: '147144147',
      GV: '147153162'
    ;

    auth.on.success.addOnce(function(response) 
      data = response;
    );

    auth.request(OPTIONS);

    it('"status" should exist and be "true"', function() 
      waitsFor(function() 
        return data !== undefined;
      );

      runs(function() 
        expect(data['status']).toBeDefined();
        expect(data['status']).toBeTruthy();
      );
    );

  );
);

// login.js
define(['service/login'], function(login) 
  describe('Tests "login" service', function() 
    var data;
    var OPTIONS = 
      oper: 1,
      codigoouemail: '101',
      senha: '10151015'
    ;

    login.on.success.addOnce(function( response ) 
      data = response;
    );

    login.request(OPTIONS);

    it('Should get the service response for user "' + OPTIONS.codigoouemail + '"', function() 
      waitsFor(function() 
        return data !== undefined;
      );

      runs(function() 
        expect(data).toBeDefined();
      );
    );

  );
);

它们在单独测试时都可以正常工作,但我注意到它们对于data 具有相同的值。第一个运行的模块设置它的值,其他规范将具有相同的值。我需要每个模块有一个值,以便我可以正确测试每个服务响应。 理论上,每个模块都应该有自己的作用域,但看起来并没有发生这种情况。

有人知道如何解决这个问题吗?

【问题讨论】:

附带说明,Jasmine 2.0.0 现在为it() 方法提供了一个可选的done 参数,允许您使用更少的代码编写异步测试。但是,还要注意,如果您使用的是Karma test runner、Karma currently comes bundled with Jasmine 1.3.1,那么在这种情况下您将无法使用新的done 参数(至少在 Karma 更新其 Jasmine 版本之前)。 Testing Asynchronous javascript w/ Jasmine 2.0.0 是一篇很好的博文,介绍了如何使用新的 Jasmine 2.0.0 done 参数,如果您有可用的 Jasmine 版本。 @Cupcake 哦,终于!好东西。我目前正在使用 Konacha 以及 Sinon 和 Chai 进行测试。我必须再给 Jasmine 一次机会 :) 【参考方案1】:

下面是我用来检查我的VOs 是否已创建的异步测试示例:

it('should return a list of item VOs', function() 
  var dfd = $q.defer();
  var items = mock.content.items[1].items;

  runs(function() 
    dfd.promise.then(function(VOs) 
      expect(VOs.length).toBe(items.length);
      expect(A.equals(itemVO(items[0]), VOs[0])).toBe(true);
    , this.fail);
  );

  waits(50);

  runs(function() 
    itemsVO(dfd, items);

    $rootScope.$digest();
  );
);

首先我运行一个函数来监听我的异步函数何时完成,我等待 50 毫秒以检查应用程序是否准备就绪,然后我运行我的异步函数。请注意 expect 在回调中的方式。

【讨论】:

【参考方案2】:

所以这完全是我的错。这是 ajax 调用的错误,它总是给我相同的值,因此所有测试都失败了。无论如何感谢您的帮助:)

【讨论】:

【参考方案3】:

抱歉,问题不在于数据变量。 Javascript 有函数作用域,所以两个数据变量是不同的。这是一个显示数据不一样的小提琴:http://jsfiddle.net/LNuHU/2/

下面是代码:

//--- SPECS -------------------------
describe('Tests timeout service 1', function() 

        var data;

        setTimeout(function( response ) 
            data = 3;
        , 1000);


        it('Should be 3', function() 

            waitsFor(function() 
                return data !== undefined;
            );

            runs(function() 
                expect(data).toBe(3);
            );

        );


        it('Should be 30', function() 

            waitsFor(function() 
                return data === 30;
            );

            runs(function() 
                expect(data).toBe(30);
            );

        );

    );

describe('Tests timeout service 2', function() 

        var data;

        setTimeout(function( response ) 
            data = 30;
        , 2000);


        it('Should be 30', function() 

            waitsFor(function() 
                return data !== undefined;
            );

            runs(function() 
                expect(data).toBe(30);
            );

        );


        it('Should be 30', function() 

            waitsFor(function() 
                return data === 3;
            );

            runs(function() 
                expect(data).toBe(3);
            );

        );

    );

【讨论】:

是的,我知道。困扰我的是 RequireJS 应该处理函数作用域(而且它做得很好)。所以我假设问题在于 Jasmine 不能很好地处理关于函数上下文的异步代码。我什至发现有些人有同样的问题...... 嘿,伙计,现在我知道你在这里做了什么...datadescribe() 的值不同,这正是我想要的,但为什么我得不到相同的结果?当我打印data 值时,它始终是第一个response 的值。这让我很恼火......

以上是关于使用 Jasmine 进行异步测试的主要内容,如果未能解决你的问题,请参考以下文章

Jasmine:期望在异步函数中抛出错误

使用jasmine来对js进行单元测试

使用 Jasmine 和 TypeScript 进行单元测试

在异步超时时传递Jasmine规范

在Visual Studio 2013中使用Jasmine + Karma进行AngularJS测试

安装和使用Karma-Jasmine进行自动化测试