Grunt - Karma 单元测试

Karma 是 Goolge 开源的一个 Test runner, 可以配合 Grunt 使用。

1. 相关插件介绍

1.1 Karma 的官网

http://karma-runner.github.io/

官网中的文档其实分多钟版本,不同版本的 karma 使用也有所不同,注意页面右上角的版本信息。

1.2 配合 Grunt 的插件 grunt-karma

https://github.com/karma-runner/grunt-karma

1.3 karma 用来启动 chrome 的 karma 插件

https://github.com/karma-runner/karma-chrome-launcher

1.4 jasmine 单元测试插件

https://github.com/karma-runner/karma-jasmine

1.5 单元测试的报表格式

单元测试默认提供了两种输出:‘dots‘, ‘progress‘ ,都比较简单,希望看到测试的详细输出,可以使用 reporter 插件,这里是其中之一:mocha

https://github.com/litixsoft/karma-mocha-reporter

1.6 angularJS 插件

https://github.com/karma-runner/karma-ng-scenario

1.7 requirejs 模块化插件

https://github.com/karma-runner/karma-requirejs

2. 安装插件

2.1 创建 package.json

使用 npm init 来创建 package.json 项目文件。

PS C:\study\demo> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (demo) demo
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC) MIT
About to write to C:\study\demo\package.json:

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

Is this ok? (yes) y
PS C:\study\demo>

安装 grunt-karma 插件。

PS C:\study\demo> npm install grunt-karma --save-dev
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
grunt[email protected]0.12.1 node_modules\grunt-karma
└── [email protected]3.10.1

安装之后,在 node_modules 中实际上有了 grunt, grunt-karma, 以及 karma 三个组件。

继续安装 karma 的插件。

先安装 chrome 的启动器。

PS C:\study\demo> npm install --save-dev karma-chrome-launcher
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
karma[email protected]0.2.0 node_modules\karma-chrome-launcher
├── fs[email protected]1.0.0 (null[email protected]1.0.0)
└── which@1.1.2 ([email protected]0.1.7)

单元测试 jasmine.

PS C:\study\demo> npm install --save-dev karma-jasmine
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
npm WARN peerDependencies The peer dependency jasmine[email protected]* included from karma-jasmine will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
jasmine[email protected]2.3.4 node_modules\jasmine-core

karma[email protected]0.3.6 node_modules\karma-jasmine

单元测试的输出报表格式 mocha.

PS C:\study\demo> npm install --save-dev karma-mocha-reporter
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
karma[email protected]1.1.1 node_modules\karma-mocha-reporter
└── [email protected]1.1.0 (escape-string[email protected]1.0.3, [email protected]2.0.0, [email protected]2.1.0, [email protected]2.0.0, [email protected]3.0.0)

angular 插件

PS C:\study\demo> npm install --save-dev karma-ng-scenario
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
karma[email protected]0.1.0 node_modules\karma-ng-scenario

requirejs 插件。

PS C:\study\demo> npm install --save-dev karma-requirejs
npm WARN package.json [email protected]1.0.0 No description
npm WARN package.json [email protected]1.0.0 No repository field.
npm WARN package.json [email protected]1.0.0 No README data
npm WARN peerDependencies The peer dependency [email protected]~2.1 included from karma-requirejs will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
[email protected]2.1.20 node_modules\requirejs

karma[email protected]0.2.2 node_modules\karma-requirejs

3. 配置

不用版本的 karma 配置会有所不同,这里使用 v0.13 版。

karma 的运行配置可以保存在独立的文件中,也可以在 Gruntfile.js 中直接配置,由于 karma 的配置参数较多,建议保存在独立的配置文件中。

这样,我们可以针对不同的测试场景,创建不同的 karma 配置文件,最后通过 grunt 来使用。

karma 配置文件中的 basePath 是一个非常重要的参数,用来表示 karma 配置文件中的其它相对路径所依赖的起点。

如果这是一个对象路径,就会相对于配置文件来定位。

默认是 ‘‘, 也就是说配置文件所在的目录就是相对的根目录了。

在 karma 实际运行的时候,这个目录会被自动映射到 /base 之下。

files 中配置可以通过 karma 服务器访问哪些文件,在这里列出的文件,才可以通过 HTTP 访问到。当使用对象方式表示路径的时候,included 表示 karma 是不是需要自动生成一个 script 标记来加载特定的脚本,设置为 false 表示不生成这个标记,而 served 则表示是否可以通过 karma 的网站服务器访问这个文件。

plugins 在 v0.13 中可以不同配置,karma 会自动加载位于 node_modules 中的 karma-* 的 karma 模块。

// Karma configuration
// Generated on Tue Sep 15 2015 12:41:55 GMT+0800 (China Standard Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: ‘‘,

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    // if requirejs used,
    frameworks: [‘jasmine‘, ‘requirejs‘],

    // list of files / patterns to load in the browser
    files: [

      // inclueded, default: true, should the files be included in the browser using <script> tag?
      // use false if you want to load them manually. eg using require.js
      // served, default: true, should the files be served by karma‘s webserver?
      // watched, default: true, if autowatch is true, all files that have set watched to true will be watched for change
      { pattern: ‘src/**/*.*‘, included: false, served: true },
      { pattern: ‘test/**/*_spec.js‘, included: false, served: true },

      //in version 0.13, the item should be last
      ‘test-main.js‘,
    ],

    // list of files to exclude
    exclude: [
        ‘src/js/main.js‘
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: ‘dots‘, ‘progress‘
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: [‘mocha‘],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: [‘Chrome‘],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // By default, Karma loads all sibling NPM modules which have a name starting with karma-*.
  })
}

在配合 requirejs 的时候,我们还需要一个 main.js 文件对 requirejs 进行配置。

在 requirejs 中也有一个 baseUrl 配置参数,这里一定要考虑刚才karma 的 basePath 进行配置,由于在 karma 的网站中,前面又添加了 /base ,所以,现在 requirejs 的 baseUrl 就会变成 /base/src/js 了。

这样,修改了 baseUrl, 我们其它的模块 Id 就不用变化了。

我们希望能够通过 karma 直接加载测试并执行测试,所以,karma 帮助我们生成了一段脚本,从我们网站中的脚本文件中筛选出测试文件,直接加载执行,脚本通过正则表达式  /(spec|test)\.js$/i 来筛选,可以看到,它直接检查脚本文件名中,以 spec.js 或者 test.js 结尾的脚本文件。找到之后,通过 requirejs 配置中的 deps 提前加载并执行。

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, ‘‘);
    var normalizedTestModule = file;
    allTestFiles.push(normalizedTestModule);
  }
});

require.config({
  // Karma serves files under /base, which is the basePath from your config file
  baseUrl: ‘/base/src/js‘,
    paths:{
      ‘angular‘:‘lib/angular.min‘
    },
  shim:{
    ‘angular‘:{
      ‘exports‘: ‘angular‘
    }
  },

  // dynamically load all test files
  deps: allTestFiles,

  // we have to kickoff jasmine, as it is asynchronous
  callback: window.__karma__.start
});

require([‘angular‘, ‘controllers/controllers‘], function(angular, controller){
  console.log(‘main.js loaded.‘);
  console.log( controller);

}, function(){
  console.log("load error");
  console.log( arguments);
});

4. 测试的写法

比如,我们有一个模块的定义。

define([], function(){

    return function ($scope){

        $scope.name = ‘World‘;

        $scope.phones = [
            {‘name‘: ‘Nexus S‘, ‘snippet‘: ‘Fast just got faster with Nexus S.‘, ‘age‘:1 },
            {‘name‘: ‘Motorola XOOM™ with Wi-Fi‘, ‘snippet‘: ‘The Next, Next Generation tablet.‘, ‘age‘:2 },
            {‘name‘: ‘MOTOROLA XOOM™‘, ‘snippet‘: ‘The Next, Next Generation tablet.‘, ‘age‘:3 }
          ];

          $scope.orderProp = ‘age‘;
    };
})

测试也是一个模块,一定要在测试的依赖项中,将测试所依赖的模块加载进来。

// use define to load dependency block.
define([‘controllers/controllers‘], function(target) {

    // regular jasmine test case
    describe(‘PhoneCat controllers‘, function() {
        describe(‘PhoneListCtrl‘, function(){

            var scope, ctrl;

            beforeEach(function(){
                scope = {};

                // create controller instance
                ctrl = new target( scope );
            });

            it(‘should create "Phone" model with 3 phones.‘, function(){
                expect( scope.phones.length ).toBe( 3 );
            });

            it(‘ the name of "Phone" model should be "World".‘, function(){
                expect( scope.name ).toBe(‘World‘);
            });

            it(‘the age of "Phone" model should be "age",‘, function(){
                expect( scope.orderProp ).toBe( ‘age‘ );
            })
        })
    });
});

执行之后的输出如下:

PS C:\study\photocat> grunt karma
Running "karma:unit" (karma) task
16 09 2015 14:38:05.540:WARN [karma]: No captured browser, open http://localhost:9876/
16 09 2015 14:38:05.555:INFO [karma]: Karma v0.13.9 server started at http://localhost:9876/
16 09 2015 14:38:05.564:INFO [launcher]: Starting browser Chrome
16 09 2015 14:38:08.382:INFO [Chrome 44.0.2403 (Windows 7 0.0.0)]: Connected on socket IUSWkKhxqSbjN8NzAAAA with id 89877642

Start:
  hello, jasmine.
    √ say hello to jasmine.
  PhoneCat controllers
    PhoneListCtrl
      √ should create "Phone" model with 3 phones.
      √  the name of "Phone" model should be "World".
      √ the age of "Phone" model should be "age",

Finished in 0.013 secs / 0.002 secs

SUMMARY:
√ 4 tests completed

5. 总结

在配合 requirejs 的时候, karma 路径,requirejs 的路径一定要注意,karma 的服务器将我们的服务内容放在了 /base 之下,我们在使用的时候,必须特别注意这一点。

时间: 2024-10-07 12:21:55

Grunt - Karma 单元测试的相关文章

单元测试工具 - karma

在离开上一家公司之前,team leader 在我离开前留给了我最后几个关键字:karma,断言库,JASMINE,QUNIT,MOCHA. 可一直拖拖沓沓的,没有去了解.直到今天,才终于抽出心情和时间来研究它. 在文章开始之前,首先对前 team leader — 满爷 表示感激. 虽然你不是我所见过的最优秀的前端,但你是我所见的最乐意与小伙伴share经验心得的 team leader. OK,言归正传,开始主题... 关于karma Karma是一个基于Node.js的JavaScript

Karma和Jasmine自动化单元测试

前言 在Java领域,Apache, Spring, JBoss 三大社区的开源库,包罗万象,但每个库都在其领域中都鹤立鸡群.而Nodejs中各种各样的开源库,却让人眼花缭乱,不知从何下手. Nodejs领域: Jasmine做单元测试,Karma自动化完成单元测试,Grunt启动Karma统一项目管理,Yeoman最后封装成一个项目原型模板,npm做nodejs的包依赖管理,bower做javascript的包依赖管理.Java领域:JUnit做单元测试, Maven自动化单元测试,统一项目管

Karma和Jasmine自动化单元测试——本质上还是在要开一个浏览器来做测试

1. Karma的介绍 Karma是Testacular的新名字,在2012年google开源了Testacular,2013年Testacular改名为Karma.Karma是一个让人感到非常神秘的名字,表示佛教中的缘分,因果报应,比Cassandra这种名字更让人猜不透! Karma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner).该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代

karma配置文件参数介绍

目录结构 参数介绍 /*** * Created by laixiangran on 2015/12/22. * karma单元测试配置文件 */ module.exports = function(config) { config.set({ /*** * 基础路径,用在files,exclude属性上 */ basePath: "", /** * 测试框架 * 可用的框架:https://npmjs.org/browse/keyword/karma-adapter */ frame

karma+angular

下面的介绍以karma能正常运行为前提,看karma系列文章:http://www.cnblogs.com/laixiangran/tag/Karma/ 目录结构 步骤 安装 npm install angular --save-dev npm install angular-mocks --save-dev //专门用来进行单元测试的模块 karma.conf.js /*** * Created by laixiangran on 2015/12/22. * karma单元测试配置文件 */

karma+seajs

下面的介绍以karma能正常运行为前提,看karma系列文章:http://www.cnblogs.com/laixiangran/tag/Karma/ 目录结构 步骤 安装 npm install karma-seajs --save-dev karma.conf.js /*** * Created by laixiangran on 2015/12/22. * karma单元测试配置文件 */ module.exports = function(config) { config.set({

karma+requirejs

下面的介绍以karma能正常运行为前提,看karma系列文章:http://www.cnblogs.com/laixiangran/tag/Karma/ 目录结构 步骤 安装 npm install karma-requirejs --save-dev karma.conf.js /*** * Created by laixiangran on 2015/12/22. * karma单元测试配置文件 */ module.exports = function(config) { config.se

使用karma测试平时写的小demo(arguments为例)

有人说前端自动化测试非常困难,我觉得确实如此.在项目中,我个人也不放心写的测试,还是要手动测试.但是我们平时写demo学习时,完全可以使用自动化测试. 传统demo 1,新建一个html 2,写入js脚本 3,运行html 平时写demo,大家伙恐怕都是这个步骤吧,其实我们可以使用karma自动化这个过程. 自动化demo(使用karma) 假设已经安装好karma,如果不会,请看本人的这篇博客 karma单元测试入门 1,在根目录运行 karma init 一路空格选择默认,在What is

前端方案

angularjs, nodejs, express, gulp, karma, jasmine 前端方案整合 今年转向做前端开发,主要是做angularjs开发,期间接触了nodejs平台,从此一发不可收拾. npm丰富的插件库,express 开发框架, grunt, gulp构建工具,karma测试管理工具,jasmine单元测试框架,ng-scenario e2e测试框架(以前不知道javascript还能做端对端测试的),coffeescript, less, sass等前端技术,没想