【问题标题】:AngualrJS with Karma - how do I write a unit test for a factory?带有 Karma 的 AngularJS - 我如何为工厂编写单元测试?
【发布时间】:2017-01-24 07:22:56
【问题描述】:

我正在编写一个简单的 AngularJS 1.x 网络应用程序。

我有一个模块:

main.js:

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

factory.js

app.factory('DataFactory', function(){

  var DataService = {};

  DataService.something = function() {
    return 5;
  };

  return DataService;

});

controller.js

app.controller('DataController', function ($scope, DataFactory) {
    $scope.searchText = null;
    $scope.results = DataFactory.something();
});

index.html:

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8">
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</script>
    </head>
    <body ng-app="app" ng-controller="DataController">
        <script src="app.js"></script>
        <script src="factory.js"></script>
        <script src="controller.js"></script>
    </body>
</html>

测试文件:

  describe('Data Factory Test', function() {

    var Factory;

    beforeEach(function() {
      angular.module('app');
    });

    beforeEach(inject(function() {
      var $injector = angular.injector(['app']);
      Factory = $injector.get('DataFactory');
    }));

    it('is very true', function(){
        expect(Factory).toBeDefined();
      // var output = Factory.something();
      // expect(output).toEqual(5);
    });

  });

karma.conf.js:

frameworks: ['jasmine'],


// list of files / patterns to load in the browser
files: [
    'node_modules/angular/angular.js',
    'node_modules/angular-mocks/angular-mocks.js',
    'app.js',
    'factory.js',
    'controller.js',
    'test/*.js'
]

如何编写单元测试来检查工厂是否存在,并检查返回的东西?

我在运行 karma start 时不断收到错误消息: 错误:[$injector:modulerr] 无法实例化模块应用程序,原因是: 错误:[$injector:unpr] 未知提供者:$controllerProvider

编辑:我让它工作了。我将如何为有工厂和没有工厂的控制器编写单元测试?

【问题讨论】:

  • 请同时发布您在测试规范中的内容。
  • 在测试中 - 你有 OlympicDataFactory 但在你使用的代码中 DataFactory - 有一个是正确的?

标签: angularjs unit-testing karma-jasmine


【解决方案1】:

第一部分展示了如何测试服务/工厂。 第二部分展示了控制器测试的两种方式

  • 我们只是期望 $scope 中的一些变量已更改
  • 我们预计某些服务/工厂已被调用

可能所有这些类型的测试都能满足我们的所有需求。

angular.module('app', []).factory('DataFactory', function() {

  var DataService = {};

  DataService.something = function() {
    return 5;
  };

  return DataService;

}).controller('DataController', function($scope, DataFactory) {
  $scope.searchText = null;
  $scope.results = DataFactory.something();
});

describe('Data Factory Test', function() {
  var Factory;

  beforeEach(module('app'));

  beforeEach(inject(function(_DataFactory_) {
    Factory = _DataFactory_
  }));

  it('is very true', function() {
    expect(Factory).toBeDefined();
    var output = Factory.something();
    expect(output).toEqual(5);
  });
});

describe('DataController ', function() {

  var $scope, instantiateController, DataFactory

  beforeEach(module('app'));

  beforeEach(inject(function($rootScope, $controller, _DataFactory_) {
    $scope = $rootScope.$new()
    DataFactory = _DataFactory_
    instantiateController = function() {
      $controller('DataController', {
        $scope: $scope,
        DataFactory: DataFactory
      })
    }
  }))

  // It shows that controller chenges $scope.results
  it('Calculates results', function() {
    expect($scope.results).toBe(undefined)
    instantiateController()
    expect($scope.results).toBe(5)
  })

  // It shows that DataFactory was called
  it('Calls `DataFactory.something`', function() {
    spyOn(DataFactory, 'something');
    instantiateController()
    expect(DataFactory.something).toHaveBeenCalled()
  })
});
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-mocks.js"></script>

【讨论】:

  • +1 下划线符号。如果有人想知道,Underscore notation: The use of the underscore notation (e.g.: _$rootScope_) is a convention wide spread in AngularJS community to keep the variable names clean in your tests. That's why the $injector strips out the leading and the trailing underscores when matching the parameters. The underscore rule applies only if the name starts and ends with exactly one underscore, otherwise no replacing happens.
  • 谢谢!我将如何为控制器编写单元测试?您能否将其添加到您的答案中?
  • 添加了一些如何测试控制器的概念证明
【解决方案2】:

您需要拨打angular.injector:

'use strict';

(function() {
  describe('Factory Spec', function() {

    var Factory;

    beforeEach(function() {
      angular.module('app');
    });

    beforeEach(inject(function() {
      var $injector = angular.injector(['app']);
      Factory = $injector.get('DataFactory');
    }));

    it('is very true', function(){
      var output = Factory.something();
      expect(output).toEqual(5);
    });

  });
  }());

测试控制器:

describe('PasswordController', function() {
  beforeEach(module('app'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

  describe('$scope.grade', function() {
    it('sets the strength to "strong" if the password length is >8 chars', function() {
      var $scope = {};
      var controller = $controller('PasswordController', { $scope: $scope });
      $scope.password = 'longerthaneightchars';
      $scope.grade();
      expect($scope.strength).toEqual('strong');
    });
  });
});

来自here

【讨论】:

  • 我收到一个错误:错误:[$injector:modulerr] 无法实例化模块应用程序,原因是:错误:[$injector:unpr] 未知提供程序:$controllerProvider
  • 这意味着你还没有发布你的整个代码,并且在某个地方还有一个控制器需要模拟@user1261710
  • 如何为控制器执行此操作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多