AngularJS / Karma测试:beforeEach未执行

8

我正在进行一些关于AngularJS的TDD(另一个故事),遇到了一个问题,我的beforeEach调用显然没有被执行。我将其简化为以下示例。

这个示例可以工作,因为在beforeEach和it中的console.log消息都会出现:

describe('userApp', function(){ 
  beforeEach( function(){ 
    console.log("in beforeEach...");
  }); 

  it('should be able to log something', function(){ 
    console.log("in it...");
  }); 
});

这段代码不能正常工作,因为在beforeEach中的console.log消息未被显示出来,而且在尝试$log.info时测试失败并抛出错误信息:TypeError: Cannot read property 'info' of undefined

describe('userApp', function(){ 
  var $log;
  beforeEach(module('userApp', function($provide) {
    console.log("in beforeEach...");
    // Output messages
    $provide.value('$log', console);
  })); 
  it('should be able to log something', function(){ 
    console.log("in it...");
    $log.info("Using $log for logging...");
  }); 
});

我正在使用Angular 1.3.15,karma 0.12.31,jasmine 2.3.4。可能是我忽略了一些显而易见的东西...

编辑:Michael Radionov的解释非常有帮助;然而,我不明白为什么这个修改后的代码仍然会抛出相同的错误。
describe('userApp', function(){ 
  console.log("starting TEST3");   <=== this prints
  var $log;
  beforeEach(function() {
    console.log("TEST3: in beforeEach...");   <=== this prints
    module('userApp', function($provide, _$log_) {
      $log = _$log_;
      console.log("TEST3: in beforeEach/module...");   <=== never executed
      // Output messages
      $provide.value('$log', console);
      $log.info("TEST3: calling $log in beforeEach...");
    })
  }); 
  it('should be able to log something', function(){ 
    console.log("TEST3: in it...");
    $log.info("TEST3: Using $log for logging...");  <=== $log undefined err
  }); 
});

此外,“module('userApp'...”中的代码似乎从未执行过...?
1个回答

5
你的日志消息 console.log("in beforeEach..."); 没有被显示出来的原因是它实际上不在 beforeEach 中,而是在传递给 module(..) 作为参数的匿名函数中,这个匿名函数被 angular-mocks 视为一个模块。只有当注入发生时,该模块才会被执行,并在同时你将收到一个日志消息 in beforeEach...,但是你的测试中没有任何注入,所以它永远不会发生。无论如何,beforeEach 都会触发,你只是没有把 console.log 放在正确的位置;这样做就可以了:
beforeEach(function () {

  console.log("in beforeEach...");

  module('userApp', function($provide) {
    // Output messages
    $provide.value('$log', console);
  });

});

此外,看起来您忘记将模拟的$log注入到测试套件中,您的$log变量从未获得任何值,因此它保持为未定义状态,正如错误所述。
describe('userApp', function(){ 

  var $log;

  beforeEach(function () {
    console.log("in beforeEach...");

    module('userApp', function($provide) {
      // Output messages
      $provide.value('$log', console);
    });

    // getting an instance of mocked service to use in a test suite
    inject(function (_$log_) {
      $log = _$log_;
    });

  }); 

  it('should be able to log something', function(){ 
    console.log("in it...");
    $log.info("Using $log for logging...");
  }); 

});

请查看plunker:http://plnkr.co/edit/EirNEthh4CXdBSDAeqOE?p=preview

文档:


谢谢,迈克尔...这开始有所帮助了。我将使用另一个样例更新帖子,它似乎应该可以工作。听起来,即使beforeEach()都被执行了,它们内部的module()代码也不一定会同时执行? - JESii
在你的更新中,你尝试使用module()注入_$log_,但这样是行不通的。module()仅用于注册模块,当你调用inject()时将执行这些模块。注入是由注射器完成的工作。如果你在这里立即调用inject(),它可能被视为“同时”。在我的示例中,我已经将inject移动到同一个beforeEach中,以使其更清晰明了。 - Michael Radionov
谢谢你,Michael。你解释得非常好。然而,在我看来,这就是Angular开始变得疯狂的地方。如果我首先放置“inject”,然后是“module”语句,那么我会得到“Injector already created, can not register a module!”(注射器已经创建,无法注册模块!)。有一个关于这个问题的讨论在 Stack Overflow 上https://dev59.com/-mAf5IYBdhLWcg3wOQYL,有很多不同的方法......请注意对@gilamarn答案的争议。似乎在Angular中进行测试非常挑剔。 - JESii
我想知道为什么需要在“module”之前进行“inject”。试着从这个角度来看待问题:module像在真实应用中一样注册你的模块/服务/工厂/控制器;而inject则启动了该应用。如果你首先调用“inject”(意味着你的应用已经启动),那么你将无法在此后注册新的模块并再次调用“inject”(重新启动应用)。同样适用于测试工作流程。这个例子非常宽泛,但可以帮助理解。 - Michael Radionov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接