Karma测试(Karma + AngularJS + RequireJS)

1. 简介

Karma是一种用于自动化测试的工具。
本文共包含4个例子: Karma -> Karma + AngularJS -> Karma + RequireJS -> Karma + AngularJS + RequireJS。
代码均已上传至我的Github,下载完成后至相应目录下执行 karma start 即可开始单元测试。

2. 使用karma搭建一个简单的测试demo

  1. 初始化项目
    npm init
    
  2. 安装必要的依赖
    npm install karma --save-dev
    npm install jasmine-core --save-dev
    
  3. 初始化karam测试配置
    karma init
    
    这里全部回车,按照默认选项即可
    karma init执行完成后会生成配置文件karma.conf.js。这个文件实质上就是一个js。
    在该文件的config.set({...})中有一个key为files的参数,其用于指定当开始执行测试时,我们需要浏览器载入的js文件。
  4. 在根目录下创建index.js和test.js,其中index.js包含一个反转字符串的函数reverseString(),我们将使用test.js对其进行测试test.js中的内容:
    ```
    describe(“karma demo - it is a simple test”, function(){
    it(“testing function reverseString - test case 1”, function(){
    expect(reverseString(“123”)).toBe(“321”);
    });
    it(“testing function reverseString - test case 2”, function(){
    expect(reverseString(“121”)).toBe(“121”);
    });
    });
5. 修改``karma.conf.js``中``config.set({..})``里的files, 将这两个文件引入测试浏览器中(Karma通过files数组指定测试过程中需要使用的js文件):  
```javascript
files: [
  'index.js',
  'test.js'
],

在根目录执行karma start即可开始执行测试
本部分代码可参考1_karma_begin

3. karma + AngularJS

  1. 重复上一节中的1~3, 并安装Angular相关依赖:(注意 - angularangular-mocks 版本号要一致)
    npm install angular --save-dev
    npm install angular-mocks --save-dev
    
  2. 新建scripts文件夹,加入app.js和appSpec.js
    app.js:

    var app = angular.module('myApp', []);
    app.controller('myController', function($scope){
    $scope.reverseString = function(str){
     return str.split('').reverse().join('');
    }
    });
    

    appSpec.js:

    describe("karma demo - it is a demo combine AngularJS", function(){
     var scope = null;
    
     beforeEach(module('myApp'));
     beforeEach(inject(function($rootScope, $controller){
       scope = $rootScope.$new();
       $controller('myController', {$scope: scope});
     }));
    
     it("testing - test case 1", function(){
       expect(scope.reverseString("123")).toBe("321");
     });
    });
    
  3. 修改karma.conf.js:
    ...
    files: [
    'node_modules/angular/angular.js',
    'node_modules/angular-mocks/angular-mocks.js',
    'scripts/app.js',
    'scripts/appSpec.js'
    ],
    ...
    
    在根目录执行karma start即可开始执行测试
    本部分代码可参考2_karma_angularjs

    4. karma + RequireJS

  4. 初始化项目
    npm init
    
  5. 安装必要的依赖
    npm install karma --save-dev
    npm install jasmine-core --save-dev
    npm install requirejs --save-dev
    npm install karma-requirejs --save-dev
    
  6. 初始化karam测试配置
    karma init
    
    在这两个问题中选择yes
    Do you want to use Require.js ? - yes - 在测试中使用RequireJS
    Do you wanna generate a bootstrap file for RequireJS? - yes - 生成一个RequireJS的配置文件
    初始化完成后可以看到根目录下多了karma.conf.js和test-main.js两个文件,且在karma.conf.js的config.set({...})中的files数组中已写入了test-main.js,也就是说开始测试后会自动执行test-main.js
  7. karma.conf.js
    在karma.conf.js中可看到这么一段代码:
    ...
    files: [
     'test-main.js',
    ],
    ...
    
    这里的files指定了浏览器执行测试工作时需要载入的js文件,这里指定了 test-main.js 后浏览器在开始测试时会以 <script>.../test-main.js</script> 的形式载入 test-main.js,如图所示。
  8. test-main.js
    test-main.js中产生代码为:

    var allTestFiles = []
    var TEST_REGEXP = /(spec|test)\.js$/i
    
    // Get a list of all the test files to include
    Object.keys(window.__karma__.files).forEach(function (file) {
     if (TEST_REGEXP.test(file)) {
       // Normalize paths to RequireJS module names.
       // If you require sub-dependencies of test files to be loaded as-is (requiring file extension)
       // then do not normalize the paths
       var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '')
       allTestFiles.push(normalizedTestModule)
     }
    })
    
    require.config({
     // Karma serves files under /base, which is the basePath from your config file
     baseUrl: '/base',
    
     // dynamically load all test files
     deps: allTestFiles,
    
     // we have to kickoff jasmine, as it is asynchronous
     callback: window.__karma__.start
    })
    

    可以看到(第3行),系统会遍历 window.__karma__.files ,自动将含有匹配TEST_REGEXP的js文件当做测试脚本(第20行)。
    这里的 window.__karma__.files 就是浏览器在执行测试时会载入的所有js文件的集合。
    window.__karma__.files中包含了上一小节中 karma.conf.jsfiles 数组中指定的文件。
    requre.config({...})中的baseUrl是karma默认的根目录,对应项目工程中的根目录 ‘/‘

  9. 增加测试文件
    创建文件夹scripts,在其中增加待测试文件src.js和测试文件srcSpec.js
    src.js:
    define('src', function(){
     var testObj = {};
     testObj.returnTrue = function(){
       return true;
     }
     return testObj;
    });
    
    srcSpec.js:
     define(['src'], function(srcObj){
       describe("karma demo - it is a demo combine requireJS", function(){
         it("testing - test case 1", function(){
           expect(srcObj.returnTrue).toBe(true);
         });
       });
     });
    
  10. 加载要测试的js文件
    这时执行karma start,提示执行了0个测试用例-需要把代码加入karma.conf.jsconfig.set({..})files数组,否则测试浏览器不知道要加载这些js文件。
    karma.conf.js中的files修改为:

    files: [
     {pattern: 'scripts/*.js', included: false},
     'test-main.js'
    ],
    

    这里的 included: false 代表是否在浏览器中采用 <script></script> 标签的方式加入该js文件。
    在使用RequireJS的情况下,应该将其设为 false ,避免测试浏览器将其采用 <script></script> 的方式引入这些JS文件。
    继续报错 - 404,找不到/base/src.js - 在 test-main.js 里观察 window.__karma__.files ,如图所示,我们可以看到引入的 src.js 实际路径为 /base/srcipts/src.js

    在test-main.js的requre.config({...})中的baseUrl对应的是工程中的根目录‘/‘,所以我们应该将src.js/srcSpec.js中的 define('src', ... 改为 define('scripts/src', ... (当然,也可以在test-main.js的require.config通过paths手动指定: paths: {'src': 'scripts/src'} )。

    在根目录执行karma start即可开始执行测试
    本部分代码可参考3_karma_requirejs

5. Karma + AngularJS + RequireJS

  1. 初始化项目
    npm init
    
  2. 安装必要的依赖
    npm install karma --save-dev
    npm install jasmine-core --save-dev
    npm install requirejs --save-dev
    npm install karma-requirejs --save-dev
    npm install angular --save-dev
    npm install angular-mocks --save-dev
    
  3. 初始化karam测试配置 - 参照上一节
  4. 新建scripts文件夹,在scripts文件夹其中增加myApp.js/myController.js/myAngularSpec.js:
    myApp.js:

    define('myApp', ['angular'], function(){
    var app = angular.module('myApp', []);
    return app;
    });
    

    myController.js:

    define('myController', ['myApp'], function(app){
     app.controller('myController', function($scope){
       $scope.reverseString = function(str){
         return str.split('').reverse().join('');
       }
     });
    });
    

    mySpec.js:

     define(['myController'], function(){
       describe("karma demo - it is a demo combine AngularJS", function(){
         var scope = null;
    
         beforeEach(module('myApp'));
         beforeEach(inject(function($rootScope, $controller){
           scope = $rootScope.$new();
           $controller('myController', {$scope: scope});
         }));
    
         it("testing - test case 1", function(){
           expect(scope.reverseString("123")).toBe("321");
         });
       });
     });
    
  5. karma.conf.js 中引入这些js:
    files: [
    'node_modules/angular/angular.js',
    'node_modules/angular-mocks/angular-mocks.js',
    {pattern: 'scripts/*.js', included: false},
    'test-main.js'
    ],
    
  6. test-main.jsrequire.config 中指定路径 paths :
    ...
    paths: {
    'myApp': 'scripts/myApp',
    'myController': 'scripts/myController',
    'angular': 'node_modules/angular/angular'
    },
    ...
    
    在根目录执行karma start即可开始执行测试
    本部分代码可参考4_karma_angularjs_requirejs