unit-testing - KarmaJS、Jasmine、RequireJS 等 : How to Use Require for Testing Modules

标签 unit-testing requirejs jasmine karma-runner karma-jasmine

使用 RequireJS 运行 Karma + Jasmine 测试——起步
帮助! . . . _ _ _ 。 . .求救!
目前,我有一个练习项目来熟悉 KarmaJS —— 以及整个单元测试。广泛的问题是,我真的对 Karma 在幕后所做的事情没有透明的看法,而且我似乎无法在相关领域找到足够的文档。事不宜迟……
这是我的文件夹结构 :

root
    |-/lib
        |-/[dependencies] (/angular, /angular-mocks, /bootstrap, /etc)  # from bower
    |-/src                                                              
        |-/[unreferenced directories] (/js, /css, /views)               # not referenced anywhere
        |-app.js                                                        # sets up angular.module('app', ...)
        |-globals.js                                                    # may be referenced in RequireJS main file; not used.
        |-index.html                                                    # loads bootstrap.css and RequireJS main file
        |-main.js                                                       # .config + require(['app', 'etc'])
        |-routeMap.js                                                   # sets up a single route
        |-test-file.js                                                  # *** simple define(function(){ return {...}; })
    |-/test
        |-/spec
            |-test-test-file.js                                         # *** require || define(['test-file'])
    |-.bowerrc                                                          # { "directory": "lib" }
    |-bower.json                                                        # standard format
    |-karma.conf.js                                                     # *** HELP!
    |-test-main.js                                                      # *** Save Our Souls!!!

karma .conf.js
// Karma configuration
// Generated on Wed Nov 19 2014 15:16:56 GMT-0700 (Mountain 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
    frameworks: ['jasmine', 'requirejs'],


    // list of files / patterns to load in the browser
    files: [
      //'test/spec/test-test-file.js',
      //'lib/**/*.js',
      //'src/**/*.js',
      //'test/spec/**/*.js',
      'test-main.js',
      {pattern: 'lib/**/*.js', included: false},
      {pattern: 'src/**/*.js', included: false},
      {pattern: 'test/spec/*.js', included: true}
    ],


    // list of files to exclude
    exclude: [
        'lib/**/!(angular|angular-mocks|angular-resource|angular-route|require|text).js',
        'lib/**/**/!(jquery|bootstrap).js',
        'src/app.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: ['progress'],


    // 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
  });
};
test-main.js
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;

var pathToModule = function(path) {
    return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};

Object.keys(window.__karma__.files).forEach(function(file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(pathToModule(file));
    }
});

require.config({
    // Karma serves files under /base, which is the basePath from your config file
    baseUrl: '/base/src',
    
    paths: {
        
        angular: '../lib/angular/angular',
        ngRoute: '../lib/angular-route/angular-route',
        jquery: '../lib/jQuery/dist/jquery',
        bootstrap: '../lib/bootstrap/dist/js/bootstrap',
        models: 'models',
        controllers: 'controllers',
        globals: 'globals',
        routeMap: 'routeMap'
    },
    shim: {
        angular: {
            exports: 'angular'
        },
        ngRoute: {
            deps: ['angular']
        },
        jquery: {
            exports: '$'
        },
        bootstrap: {
            deps: ['jquery']
        }
    },

    // dynamically load all test files
    deps: allTestFiles,

    // we have to kickoff jasmine, as it is asynchronous
    callback: window.__karma__.start
});
测试测试文件.js
console.log('....................');

define(function(){
    //console.log('testing test-file', testFile);
    
    describe('Testing testing', function(){
        it('should work', function(){
            expect(true).toEqual(true);
        });
    });

});
测试文件.js
define('testFile', [], function(){
    
    return function init(sandbox){
        var app, application = app = sandbox.app
          , globals = sandbox.globals;
        
        return {
            some: 'module'
        };
    };
    
});

问题和说明
我很想听到答案的关键点是
  • { 模式:'...', 是什么意思?包括:真|假 } 做?
  • 排除凉亭目录中所有额外内容的最佳方法。
  • 我需要在 test-main.js 文件中包含哪些文件?
  • 我需要在 karma.conf.js 文件中包含哪些文件?
  • test-main.js 实际上做了什么;这是为了什么?

  • 我收到错误和问题的时间是在我将规范包装在 define(...) 中时call -- 当我给模块一个 ID 时的事件 -- define('someId', function(){ ... }) -- 我需要从这个模块中返回一些东西吗,因为它是 define称呼?
    其他时候,我会收到“ol ERROR: 'There is no timestamp for/base/src/app.js!”。 “当然是时间戳!我真是太傻了……”——这到底是什么意思?!有时我会得到臭名昭著的“Executed 0 of 0 ERROR”——我也可以在这里澄清一下。真的,我收到很多 ERROR: '...no timestamp...' 错误——甚至是 404 s 似乎我应该使用 karma.conf.js files 拉入该库配置...???
    甚至似乎通常当我明确告诉 karma 排除 src/app.js我仍然得到 404 s 和错误。
    tl;博士
    显然,我对 Karma 和 *DD 大体上有点困惑......
    我可以运行 test-test-file.js很好,当我的 karma.conf.js files数组看起来像 [ 'test-main.js', 'test/spec/test-test-file.js' ] -- 但是,如果我将测试包装在 RequireJS 定义调用中,我会得到上面提到的“不匹配匿名定义()”错误。
    似乎当我添加 { pattern: '...', include: } 那么 karma 就不会为给定的模式添加我的任何文件(???)。
    如果有人甚至可以简单地指导我如何将 RequireJS 与 Karma 一起使用——也就是说,我可以将我的测试包装在一个 define/require 调用中并拉入我想要测试的模块......那将不胜感激。
    由于保持这些类型的问题简短并仍然提供足够的信息有点困难,我希望我没有把它弄得太长。

    编辑
    在阅读了 glepretre 的答案和我自己的一些摆弄之后,我重新配置了我的项目,如下所示:
  • 已移动 test-main.jstest/test-main.js ,
  • 将 test-test-file.js 重命名为 testFileSpec.js -- 将其从 test/spec 移出至test/ ,

  • karma.conf.js:
    ...
    // list of files / patterns to load in the browser
    files: [
        {pattern: 'lib/**/*.js', included: false},
        {pattern: 'src/**/*.js', included: false},
        {pattern: 'test/**/*Spec.js', included: false},
        
        'test/test-main.js'
      
    ],
    ....
    
    测试/test-main.js:
    /* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
    var allTestFiles = [];
    var TEST_REGEXP = /(spec|test)\.js$/i;
    
    var pathToModule = function(path) {
        return path.replace(/^\/base\//, '').replace(/\.js$/, '');
    };
    
    Object.keys(window.__karma__.files).forEach(function(file) {
        if (TEST_REGEXP.test(file)) {
            // Normalize paths to RequireJS module names.
            allTestFiles.push(pathToModule(file));
        }
    });
    */
    
    var tests = [];
    for (var file in window.__karma__.files) {
        if (/Spec\.js$/.test(file)) {
            tests.push(file);
        }
    }
    
    require.config({
        // Karma serves files under /base, which is the basePath from your config file
        baseUrl: '/base/src',
        
        paths: {},
        shim: {},
    
        // dynamically load all test files
        //deps: allTestFiles,
        //
        deps: tests,
    
        // we have to kickoff jasmine, as it is asynchronous
        callback: window.__karma__.start
    });
    
    我现在正在成功运行单元测试!特别感谢 glepretre 和所有其他贡献者。

    感谢您的任何见解:)

    最佳答案

    好的,我将尝试一次解决每个问题:
    问题1

    • what does { pattern: '...', included: true|false } do?

    Karma 的默认行为是:
  • 查找与 匹配的所有文件 pattern (强制属性)
  • 观察它们的变化( watched 选项),以便在编辑代码时重新启动单元测试以提供实时结果(只有将默认值 autoWatch 保留为 true 时才有效)。
  • 使用自己的网络服务器为他们服务( served 选项)
  • 使用 <script> 将它们包含在浏览器中( included 选项)

  • 因此,在 karma 配置的 files 数组中,您可以通过仅添加字符串模式来使用默认行为:

    files: [
      // this will match all your JS files 
      // in the src/ directory and subdirectories
      'src/**/*.js'
    ]
    
    或者使用完整的对象语法来自定义每个选项:
    files: [
      {pattern: 'src/**/*.js', watched: true, served: true, included: false}
    ]
    
    使用 requireJS,你不希望它们被包含,因为它会与 requireJS 的行为冲突!

    Included. Description: Should the files be included in the browser using <script> tag? Use false if you want to load them manually, eg. using Require.js.


    karma/config/files docs
    注意:注意在数组中添加文件/模式的顺序。很重要!如需更多了解,请在您的 karma 配置中设置 logLevel: config.LOG_DEBUG
    问题2
    • what files do I need to include in the karma.conf.js file?

    至少为单元测试的组件正常运行所需的所有文件。
    基本上,您的 define([])require() block 中列出的所有文件。
    问题3
    • best way to exclude all the extra stuff inside the bower directories.

    你到底想做什么?
    根据我之前写的内容,您可以看到您可以选择性地添加测试中需要的文件。
    当我的凉亭包使用模板时,我使用添加模式 '/bower_components/**/*.js' 甚至 '/bower_components/**/*.html'。如果这是您所担心的,我从未注意到任何重大的性能问题......由您来定义您需要的文件模式。
    问题 4 & 5
    • what does test-main.js actually do; what's it for?

    • what files do I need to include in the test-main.js file?

    test-main.js 文件的目的是在启动 Karma 之前查找并加载您的测试文件。它连接了 Karma 和 requireJS 之间的点
    您必须选择一个约定来命名您的测试文件,然后定义 TEST_REGEXP 以匹配所有这些文件。
    “官方” angular style guide and best practices for app structure 建议使用后缀 *_test.js
    编辑:您的正则表达式不起作用,因为它被定义为在末尾捕获 "spec.js" || "test.js" 或您的规范文件名以 "file.js" 结尾;)请参阅 http://regex101.com/r/bE9tV9/1
    还有一件事
    我希望我足够清楚。您可以使用 Angular + Require: angular-requirejs-ready 查看我们项目的入门应用程序结构。它已经使用 Karma 和 Protractor 进行了设置和测试。

    关于unit-testing - KarmaJS、Jasmine、RequireJS 等 : How to Use Require for Testing Modules,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27050180/

    相关文章:

    javascript - 模拟 Angular 模型的 $http.put 结果 - 单元测试

    unit-testing - R 语言中单元测试支持的现状如何

    visual-studio-2012 - Typescript 为什么以及何时需要 requirejs

    typescript - 桶装进口似乎打破了装载顺序

    javascript - 有没有正确的方法来处理 require.js 的 DOM 就绪事件? (不,domReady 插件不起作用)

    javascript - requirejs - 如何根据条件加载模块 - 什么解决方案是好的

    JavaScript - AngularJS promise 不返回任何东西

    python - 如何围绕现有产品构建测试套件?

    androidTest 目录中的 AndroidManifest 被忽略

    php - 没有连接到数据库的 Laravel 模型工厂