猜猜是错误地通过了测试

天健

我正在尝试为返回角度承诺($ q库)的方法编写测试。

我很茫然。我正在使用Karma运行测试,我需要弄清楚如何确认该AccountSearchResult.validate()函数返回了一个承诺,确认该承诺是否被拒绝,以及检查随该承诺返回的对象。

例如,被测试的方法具有以下(简化的):

.factory('AccountSearchResult', ['$q',
  function($q) {

  return {
    validate: function(result) {
      if (!result.accountFound) {
        return $q.reject({
          message: "That account or userID was not found"
        });
      }
      else {
        return $q.when(result);
      }
    }
  };
}]);

我以为我可以写这样的测试:

    it("it should return an object with a message property", function () {
      promise = AccountSearchResult.validate({accountFound:false});
      expect(promise).to.eventually.have.property("message"); // PASSES
    });

这样就过去了,但是(错误地)也是如此:

    it("it should return an object with a message property", function () {
      promise = AccountSearchResult.validate({accountFound:false});
      expect(promise).to.eventually.have.property("I_DONT_EXIST"); // PASSES, should fail
    });

我试图“最终”使用chai-promise,但我的所有测试均以误报通过:

    it("it should return an object", function () {
      promise = AccountSearchResult.validate();
      expect(promise).to.eventually.be.an('astronaut');
    });

将通过。在查看文档和SO问题时,我看到了以下示例:

expect(promise).to.eventually.to.equal('something');
return promise.should.eventually.equal('something');
expect(promise).to.eventually.to.equal('something', "some message about expectation.");
expect(promise).to.eventually.to.equal('something').notify(done);
return assert.becomes(promise, "something", "message about assertion");
wrapping expectation in runs() block
wrapping expectation in setTimeout()

使用.should给了我Cannot read property 'eventually' of undefined我想念什么?

天健

事实证明,@runTarm的建议都是正确的。我认为问题的根源是angular的$ q库与angular的$ digest周期捆绑在一起。因此,在调用$ apply时,我相信它起作用原因是因为$ apply最终仍然会调用$ digest。通常,我认为$ apply()是一种让角度了解其世界之外发生的事情的方法,但在我看来,在测试的情况下,解决$ q promise的问题.then()/.catch()可能需要推动在运行期望值之前,因为$ q被直接烘焙为角度。唉。

我能够使它以3种不同的方式工作,一种带有runs()块(和$ digest / $ apply),另外两种没有runs()块(和$ digest / $ apply)。

提供一个完整的测试可能是过分的,但是在寻找答案时,我发现自己希望人们发布他们如何注入/存根/设置服务以及不同的expect语法,因此我将发布整个测试。

describe("AppAccountSearchService", function () {
  var expect = chai.expect;

  var $q,
    authorization,
    AccountSearchResult,
    result,
    promise,
    authObj,
    reasonObj,
    $rootScope,
    message;

  beforeEach(module(
    'authorization.services',     // a dependency service I need to stub out
    'app.account.search.services' // the service module I'm testing
  ));

  beforeEach(inject(function (_$q_, _$rootScope_) {
    $q = _$q_;                  // native angular service
    $rootScope = _$rootScope_;  // native angular service
  }));

  beforeEach(inject(function ($injector) {
    // found in authorization.services
    authObj = $injector.get('authObj'); 
    authorization = $injector.get('authorization');

    // found in app.account.search.services
    AccountSearchResult = $injector.get('AccountSearchResult'); 
  }));

  // authObj set up
  beforeEach(inject(function($injector) {
    authObj.empAccess = false; // mocking out a specific value on this object
  }));

  // set up spies/stubs
  beforeEach(function () {
    sinon.stub(authorization, "isEmployeeAccount").returns(true);
  });

  describe("AccountSearchResult", function () {

    describe("validate", function () {

      describe("when the service says the account was not found", function() {

        beforeEach(function () {
          result = {
            accountFound: false,
            accountId: null
          };

          AccountSearchResult.validate(result)
            .then(function() {
              message = "PROMISE RESOLVED"; 
            })
            .catch(function(arg) {
              message = "PROMISE REJECTED";
              reasonObj = arg;
            });
          // USING APPLY... this was the 'magic' I needed
          $rootScope.$apply();
        });

        it("should return an object", function () {
          expect(reasonObj).to.be.an.object;
        });

        it("should have entered the 'catch' function", function () {  
          expect(message).to.equal("PROMISE REJECTED");
        });

        it("should return an object with a message property", function () {
          expect(reasonObj).to.have.property("message");
        });
        // other tests...
      });


      describe("when the account ID was falsey", function() {
        // example of using runs() blocks.
        //Note that the first runs() content could be done in a beforeEach(), like above
        it("should not have entered the 'then' function", function () {  
          // executes everything in this block first.
          // $rootScope.apply() pushes promise resolution to the .then/.catch functions
          runs(function() {
            result = {
              accountFound: true,
              accountId: null
            };

            AccountSearchResult.validate(result)
              .then(function() {
                message = "PROMISE RESOLVED"; 
              })
              .catch(function(arg) {
                reasonObj = arg;
                message = "PROMISE REJECTED"; 
              });

            $rootScope.$apply();
          });

          // now that reasonObj has been populated in prior runs() bock, we can test it in this runs() block.
          runs(function() {
            expect(reasonObj).to.not.equal("PROMISE RESOLVED");
          });

        });
        // more tests.....
      });

      describe("when the account is an employee account", function() {
        describe("and the user does not have EmployeeAccess", function() {

          beforeEach(function () {
            result = {
              accountFound: true,
              accountId: "160515151"
            };

            AccountSearchResult.validate(result)
              .then(function() {
                message = "PROMISE RESOLVED"; 
              })
              .catch(function(arg) {
                message = "PROMISE REJECTED";
                reasonObj = arg;
              });
            // digest also works
            $rootScope.$digest();
          });

          it("should return an object", function () {
            expect(reasonObj).to.be.an.object;
          });

          // more tests ...
        });
      });
    });
  });
});

现在,我知道了修复程序,通过阅读测试部分下的$ q文档,可以很明显地看出来,它专门说要调用$ rootScope.apply()。由于我能够同时使用$ apply()和$ digest()来工作,因此我怀疑$ digest确实是需要调用的东西,但与文档保持一致,$ apply()可能是“最佳实践” 。

$ apply与$ digest的故障情况不错

最后,剩下的唯一谜团就是默认情况下测试通过的原因。我知道我正在达到期望(它们正在运行)。那么为什么会expect(promise).to.eventually.be.an('astronaut');成功呢?/耸肩

希望能有所帮助。感谢您朝着正确的方向前进。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

量角器:存在错误,但测试通过了

来自分类Dev

开玩笑刚刚通过了所有测试,即使它是错误的

来自分类Dev

我的代码通过了测试用例,但是在我提交时显示了错误的答案

来自分类Dev

为什么“ 123()”通过了ESLint测试?

来自分类Dev

Spring Boot 通过了应该失败的测试用例

来自分类Dev

在最新的 Visual Studio 代码 1.37.1 和最新的 pytest==5.1.1 中,所有测试都通过了,但出现错误

来自分类Dev

测试失败,并出现Integrity约束违规错误,但是在第一个测试用例中它通过了。为什么?

来自分类Dev

smartctl报告总体运行状况测试通过了,但是测试失败了?

来自分类Dev

摩卡通过了应该失败的测试(ember-mocha-adapter)

来自分类Dev

检查是否所有子测试都通过了TEST :: MORE

来自分类Dev

为什么我应该失败的Supertest测试通过了?

来自分类Dev

通过了非常长的过滤器进行dotnet测试?

来自分类Dev

即使通过了正确的道具,简单的React测试仍然失败

来自分类Dev

如何判断所有的摩卡测试是否通过了摩卡对象?

来自分类Dev

我通过了测试用例,但验证失败,为什么?

来自分类Dev

尽管所有测试都通过了 Jenkins 构建失败

来自分类Dev

验证用户通过了操作验证

来自分类Dev

我的Python代码通过了简单的测试,但由于性能限制,没有通过扩展测试

来自分类Dev

尽管单元测试确实通过了,但由于单元测试失败,所以运行了属性测试

来自分类Dev

错误:函数 Campaign::camp_detls() 的参数太少,0 正好通过了 1 预期

来自分类Dev

测试验证电子邮件的存在失败,并没有通过should,通过了工厂女工

来自分类Dev

“ apt-get dist-upgrade”报告错误“ depmod:错误:错误版本通过了uname”和各种警告

来自分类Dev

为什么加了Thread.sleep让我阿卡TestKit单元测试都通过了?

来自分类Dev

Rails控制器rspec失败,规格/控制器出现RoutingError,但通过了个别测试

来自分类Dev

检查玩家是否通过了两个大门

来自分类Dev

检查玩家是否通过了两个大门

来自分类Dev

如果用户通过了Django认证,则绕过nginx缓存

来自分类Dev

你所有的断言都通过了吗?

来自分类Dev

我运行了 smartctl,很高兴它说它通过了整体健康测试,但我担心 120 个重新分配的扇区数

Related 相关文章

  1. 1

    量角器:存在错误,但测试通过了

  2. 2

    开玩笑刚刚通过了所有测试,即使它是错误的

  3. 3

    我的代码通过了测试用例,但是在我提交时显示了错误的答案

  4. 4

    为什么“ 123()”通过了ESLint测试?

  5. 5

    Spring Boot 通过了应该失败的测试用例

  6. 6

    在最新的 Visual Studio 代码 1.37.1 和最新的 pytest==5.1.1 中,所有测试都通过了,但出现错误

  7. 7

    测试失败,并出现Integrity约束违规错误,但是在第一个测试用例中它通过了。为什么?

  8. 8

    smartctl报告总体运行状况测试通过了,但是测试失败了?

  9. 9

    摩卡通过了应该失败的测试(ember-mocha-adapter)

  10. 10

    检查是否所有子测试都通过了TEST :: MORE

  11. 11

    为什么我应该失败的Supertest测试通过了?

  12. 12

    通过了非常长的过滤器进行dotnet测试?

  13. 13

    即使通过了正确的道具,简单的React测试仍然失败

  14. 14

    如何判断所有的摩卡测试是否通过了摩卡对象?

  15. 15

    我通过了测试用例,但验证失败,为什么?

  16. 16

    尽管所有测试都通过了 Jenkins 构建失败

  17. 17

    验证用户通过了操作验证

  18. 18

    我的Python代码通过了简单的测试,但由于性能限制,没有通过扩展测试

  19. 19

    尽管单元测试确实通过了,但由于单元测试失败,所以运行了属性测试

  20. 20

    错误:函数 Campaign::camp_detls() 的参数太少,0 正好通过了 1 预期

  21. 21

    测试验证电子邮件的存在失败,并没有通过should,通过了工厂女工

  22. 22

    “ apt-get dist-upgrade”报告错误“ depmod:错误:错误版本通过了uname”和各种警告

  23. 23

    为什么加了Thread.sleep让我阿卡TestKit单元测试都通过了?

  24. 24

    Rails控制器rspec失败,规格/控制器出现RoutingError,但通过了个别测试

  25. 25

    检查玩家是否通过了两个大门

  26. 26

    检查玩家是否通过了两个大门

  27. 27

    如果用户通过了Django认证,则绕过nginx缓存

  28. 28

    你所有的断言都通过了吗?

  29. 29

    我运行了 smartctl,很高兴它说它通过了整体健康测试,但我担心 120 个重新分配的扇区数

热门标签

归档