【问题标题】:Angularjs: angular-phonecat tutorial app fails first unit testAngularjs:angular-phonecat 教程应用程序第一次单元测试失败
【发布时间】:2013-10-24 13:41:55
【问题描述】:

刚开始学习 Angularjs 和使用 jasmine 进行单元测试...

按照http://docs.angularjs.org/tutorial/step_02 上的教程,发现第一个单元测试(应该通过,因为scope.phones.length 是 3)失败。

INFO [karma]: Karma v0.10.2 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 30.0.1599 (Mac OS X 10.8.5)]: Connected on socket BdjA1lVT9OOo8kgQKLYs
Chrome 30.0.1599 (Mac OS X 10.8.5) PhoneCat controllers PhoneListCtrl should create "phones" model with 3 phones FAILED
    ReferenceError: PhoneListCtrl is not defined
        at null.<anonymous> (/Applications/MAMP/htdocs/angular-phonecat/test/unit/controllersSpec.js:12:22)
Chrome 30.0.1599 (Mac OS X 10.8.5): Executed 2 of 2 (1 FAILED) (0.37 secs / 0.033 secs)

所以基本上,它说明 PhoneListCtrl 没有定义。但是该应用程序运行良好,考虑到我在教程的开头,我真的不知道从哪里开始!

这是我的单元测试,这是教程中的默认设置。

test/unit/controllerSpec.js

'use strict';

/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){

    beforeEach(module('phonecatApp'));

    it('should create "phones" model with 3 phones', function() {
      var scope = {},
          ctrl = new PhoneListCtrl(scope);

      expect(scope.phones.length).toBe(3);
    });

    it('should create "phones" model with 3 phones', inject(function($controller) {
      var scope = {},
          ctrl = $controller('PhoneListCtrl', {$scope:scope});

      expect(scope.phones.length).toBe(3);
    }));

  });
});

app/js/controller.js

'use strict';

/* Controllers */

var phonecatApp = angular.module('phonecatApp', []);

phonecatApp.controller('PhoneListCtrl', function PhoneListCtrl($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
  $scope.hello = "Hello World";
});

config/karma.conf.js http://pastebin.com/PPWjSmyJ

【问题讨论】:

    标签: unit-testing angularjs jasmine


    【解决方案1】:

    示例中有 2 个单元测试(2 个 it 块)。它们看起来应该做同样的事情,但只有第二个实际创建了您的控制器。

    当您在 Angular 中定义控制器时,它不是一个全局可用的对象,您可以使用 new Controller(...) 进行初始化。您必须从 Angular 请求它。

    您的第二个测试(似乎通过了)通过注入 $controller 服务来执行此操作,该服务将执行设置和请求控制器所需的任何操作。

    inject(function($controller) { ... });
    

    然后它像这样使用这个服务创建控制器

    var scope = {},
        ctrl = $controller('PhoneListCtrl', {$scope:scope});
    

    在您的第一个测试中,您尝试直接使用PhoneListCtrl 变量。正如错误所说,除非您在函数中定义具有该名称的变量,否则这不存在。


    我刚刚注意到教程中的测试失败。如果您在全局命名空间上定义了一个控制器,这是专门针对的。例如

    function PhoneListCtrl($scope) {
      $scope.phones = [
        {'name': 'Nexus S',
         'snippet': 'Fast just got faster with Nexus S.'},
        {'name': 'Motorola XOOM™ with Wi-Fi',
         'snippet': 'The Next, Next Generation tablet.'},
        {'name': 'MOTOROLA XOOM™',
         'snippet': 'The Next, Next Generation tablet.'}
      ];
      $scope.hello = "Hello World";
    };
    phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
    

    然后测试将起作用,因为您已在全局范围内定义了用作控制器的函数,因此您可以测试它而无需注意它是控制器的事实。这意味着如果您尝试使用其他服务,您将不得不自己注入它们并执行$controller 将为您执行的任何操作。

    【讨论】:

    • 感谢您的详细解答。因此,如果我理解正确,第一个测试正确地失败了,因为 PhoneListCtrl 是命名空间的。第一个测试在全局命名空间中查找 PhoneListCtrl。
    • 正确。第一个测试将PhoneListCtrl 视为一个在全局级别定义的javascript 变量(即不在另一个函数内部)。您的代码在将其注册为控制器时在参数内定义了控制器功能。所以它永远不会留在全局命名空间中。
    • inject 的文档在哪里? AFAICT,该功能实际上并不存在。
    • 当前文档位于docs.angularjs.org/api/angular.mock.inject。该函数在angular.mock.inject 和窗口上发布为inject
    猜你喜欢
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    相关资源
    最近更新 更多