【问题标题】:How to set up unit testing of cordova app using AngularJS, Jasmine and Karma如何使用 AngularJS、Jasmine 和 Karma 设置 Cordova 应用程序的单元测试
【发布时间】:2014-07-18 11:52:41
【问题描述】:

我正在尝试使用 Jasmine 设置 Karma 以使用 AngularJS 对我的 Cordova 应用程序进行单元测试,但我似乎无法让它运行任何测试或以某种方式将其连接到 Android 模拟器 (Genymotion)。我目前已将 Karma 设置为在 Chrome 中运行并加载我的应用程序的所有 js 文件 + 测试,但没有显示输出。我得到的只是一个显示 Karma 已连接的屏幕。当我尝试自己设置一些 Jasmine 测试并将测试文件包含在我的 index.html 页面中时,测试运行并将一些输出插入到应用程序 html 中,但我想达到我可以编写的地步测试并运行它们,而不必每次都启动实际的应用程序。

我已经尝试使用cordova launcher 插件,但实际上仍然没有发生任何事情。它列出了控制台中所有包含的文件,然后似乎完全停止(这里没有输出窗口)

是否有可能以这种方式设置单元测试,还是我注定要用console.log 语句永远乱扔我的代码?

【问题讨论】:

  • 您能否按现在的样子发布终端输出,以及您希望它的外观示例?
  • 在将单元测试放入 Cordova 应用程序之前设置单元测试怎么样?如果以前没关系,实际上更好的imo - 因为它消除了一层复杂性。我将在下面概述我们如何使用 karma 和 jasmine goodness 设置单元测试以在 grunt 中运行。

标签: angularjs unit-testing cordova jasmine karma-runner


【解决方案1】:

在 Karma/Jasmine 中为使用 cli 和 grunt 运行的 Angular 应用程序设置单元测试来完成我们的繁琐工作。

首先,您需要安装 grunt,但从现在开始,我将跳过这些废话,只为您提供或多或少的副本,了解我们如何进行单元测试。顺便说一句,效果很棒 - 我完全是单元测试狂热的一部分 - Gooble Gabble Gooble Gabble!

包.json:

{
  "name": "Kinetix-Store-Frontend",
  "version": "0.0.1",
  "devDependencies": {
    "findup-sync": "^0.1.3",
    "grunt-autoprefixer": "~0.7.3",
    "grunt-bower-install": "~1.4.0",
    "grunt-concurrent": "~0.5.0",
    "grunt-contrib-clean": "~0.5.0",
    "grunt-contrib-compass": "~0.7.2",
    "grunt-contrib-concat": "~0.4.0",
    "grunt-contrib-connect": "~0.7.1",
    "grunt-contrib-copy": "~0.5.0",
    "grunt-contrib-cssmin": "~0.9.0",
    "grunt-contrib-htmlmin": "~0.2.0",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-sass": "~0.7.3",
    "grunt-contrib-uglify": "~0.4.0",
    "grunt-contrib-watch": "~0.6.1",
    "grunt-html-snapshot": "~0.6.1",
    "grunt-karma": "~0.8.3",
    "grunt-newer": "~0.7.0",
    "grunt-ng-annotate": "^0.3.0",
    "grunt-rev": "~0.1.0",
    "grunt-svgmin": "~0.4.0",
    "grunt-usemin": "~2.1.1",
    "jasmine-reporters": "~0.4.1",
    "jshint-stylish": "~0.1.5",
    "karma": "~0.12.14",
    "karma-jasmine": "~0.2.2",
    "karma-junit-reporter": "~0.2.2",
    "karma-ng-html2js-preprocessor": "~0.1.0",
    "karma-phantomjs-launcher": "~0.1.4",
    "load-grunt-tasks": "~0.4.0",
    "time-grunt": "~0.3.1"
  },
  "engines": {
    "node": ">=0.8.0"
  },
  "dependencies": {
    "grunt": "^0.4.5"
  }
}

Karma.conf.js

// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html

module.exports = function (config) {
    config.set({
        // base path, that will be used to resolve files and exclude
        basePath: '',

        // testing framework to use (jasmine/mocha/qunit/...)
        frameworks: ['jasmine'],

        preprocessors: {
            'app/views/templates/*.tpl.html': ['ng-html2js']
        },

        // list of files / patterns to load in the browser
        files: [
            'app/bower_components/lodash/dist/lodash.js',
            'app/bower_components/angular/angular.js',
            'app/bower_components/angular-mocks/angular-mocks.js',
            'app/bower_components/angular-resource/angular-resource.js',
            'app/bower_components/angular-cookies/angular-cookies.js',
            'app/bower_components/angular-sanitize/angular-sanitize.js',
            'app/bower_components/angular-bootstrap/ui-bootstrap.js',
            'app/bower_components/angular-ui-router/release/angular-ui-router.js',
            'app/bower_components/angular-local-storage/angular-local-storage.js',
            'app/bower_components/jquery/dist/jquery.js',
            'app/bower_components/bootstrap/dist/js/bootstrap.js',
            'app/bower_components/lodash/dist/lodash.compat.js',
            'app/scripts/*.js',
            'app/scripts/**/*.js',
            'test/spec/**/*.js',

            //Templates
            'app/views/templates/*.tpl.html'
        ],


        ngHtml2JsPreprocessor: {
            stripPrefix: 'app/',
            moduleName: 'Kinetix.Templates'
        },


        // list of files / patterns to exclude
        exclude: [],

        // Reporters
        reporters: ['progress', 'junit'],

        //Config for junit
        junitReporter: {
            outputFile: './test/test-results.xml',
            suite: ''
        },

        // web server port
        port: 9001,

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


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


        // Start these browsers, currently available:
        // - Chrome
        // - ChromeCanary
        // - Firefox
        // - Opera
        // - Safari (only Mac)
        // - PhantomJS
        // - IE (only Windows)
        browsers: ['PhantomJS'],


        // Continuous Integration mode
        // if true, it capture browsers, run tests and exit
        singleRun: false
    });
};

GruntFile.js - ngMin 应该是 ngAnnotate 但我现在正在解决这个问题。如您所见,这是由 Yeoman 的 Angular Generator 为我们制作的 - 非常棒!推荐....

// Generated on 2014-01-16 using generator-angular 0.7.1
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        yeoman: {
            // configurable paths
            app: require('./bower.json').appPath || 'app',
            dist: 'dist',
            test: 'test'
        },

        configureRewriteRules: {

            options: {
                rulesProvider: 'connect.rules'
            }

        },


        // Watches files for changes and runs tasks based on the changed files
        watch: {
            js: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
                tasks: ['newer:jshint:all'],
                options: {
                    livereload: true
                }
            },
            jsTest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['newer:jshint:test', 'karma']
            },
            styles: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
                tasks: ['newer:copy:styles', 'autoprefixer']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            sass: {
                files: ['**/*.{scss,sass}'],
                tasks: ['sass:dev']

            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: '0.0.0.0',
                keepalive: true
            },


            livereload: {
                options: {
                    open: true,
                    base: [
                        '<%= yeoman.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    open: true,
                    base: ['<%= yeoman.dist %>'],
                    keepalive: true
                }
            }



        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%= yeoman.app %>/scripts/{,*/}*.js'
            ],
            test: {
                options: {
                    jshintrc: 'test/.jshintrc'
                },
                src: ['test/spec/{,*/}*.js']
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [
                    {
                        dot: true,
                        src: [
                            '.tmp',
                            '<%= yeoman.dist %>/*',
                            '!<%= yeoman.dist %>/.git*'
                        ]
                    }
                ]
            },
            server: '.tmp'
        },

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '.tmp/styles/',
                        src: '{,*/}*.css',
                        dest: '.tmp/styles/'
                    }
                ]
            }
        },

        // Automatically inject Bower components into the app
        'bowerInstall': {
            app: {
                src: ['<%= yeoman.app %>/index.html'],
                ignorePath: '<%= yeoman.app %>/'
            }
        },


        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/*.js',
                        '<%= yeoman.dist %>/styles/*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%= yeoman.dist %>/styles/fonts/*'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            html: '<%= yeoman.app %>/index.html',
            options: {
                dest: '<%= yeoman.dist %>'
            }
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            html: ['<%= yeoman.dist %>/{,*/}*.html'],
            css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],

            options: {
                assetsDirs: ['<%= yeoman.dist %>']
            }
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.{png,jpg,jpeg,gif}',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },
        svgmin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.svg',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },
        htmlmin: {
            dist: {
                options: {
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeCommentsFromCDATA: true,
                    removeOptionalTags: true
                },
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.dist %>',
                        src: ['*.html', 'views/{,*/}*.html'],
                        dest: '<%= yeoman.dist %>'
                    }
                ]
            }
        },



        // Replace With Google CDN references
        cdnify: {
            dist: {
                html: ['<%= yeoman.dist %>/*.html']
            }
        },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= yeoman.app %>',
                        dest: './.tmp/',
                        src: [
                            '*.{ico,png,txt}',
                            '.htaccess',
                            '*.html',
                            'views/{,*/}{,*/}*.html',
                            'scripts/{,*/}{,*/}{,*/}*.js',
                            'styles/{,*/}{,*/}glyphicons-*',
                            'bower_components/**/*',
                            'images/{,*/}*.{webp}',
                            'fonts/*'
                        ]
                    },
                    {
                        expand: true,
                        cwd: './.tmp/images',
                        dest: '<%= yeoman.dist %>/images',
                        src: ['generated/*']
                    }
                ]
            },
            styles: {
                expand: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },

        ngAnnotate: {
            options: {
                singleQuotes: true
            },
            dist: {
                files: [
                    {
                        expand: true,
                        src: './.tmp/scripts/{,*/}{,*/}{,*/}*.js'
                    }
                ]
            }
        },
        // Run some tasks in parallel to speed up the build process
        concurrent: {
            server: [
                'copy:styles'
            ],
            test: [
                'copy:styles',
                'shell'
            ],
            dist: [
                'copy:styles',
                'imagemin',
                'svgmin'

            ]
        },

        sass: {
            dev: {
                options: {
                    style: 'nested',
                    sourcemap: 'true',
                    'cache-location': '/tmp/sass-cache'
                },
                files: {
                    './app/styles/css/styles.css': './app/styles/sass/modules/styles.scss'
                }
            },
            dist: {
                options: {
                    style: 'compressed',
                    'cache-location': '/tmp/sass-cache'
                },
                files: {
                    './app/styles/css/styles.css': './app/styles/sass/modules/styles.scss'
                }
            }

        },
        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/styles/main.css': [
        //         '.tmp/styles/{,*/}*.css',
        //         '<%= yeoman.app %>/styles/{,*/}*.css'
        //       ]
        //     }
        //   }
        // },
        // uglify: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/scripts/scripts.js': [
        //         '<%= yeoman.dist %>/scripts/scripts.js'
        //       ]
        //     }
        //   }
        // },
        // concat: {
        //   dist: {}
        // },

        karma: {
            unit: {
                configFile: './karma.conf.js',
                singleRun: true
            }
        },


        protractor: {
            options: {
                configFile: '<%= yeoman.test %>/protractor.conf.js', // Default config file
                keepAlive: true // If false, the grunt process stops when the test fails.
            },
            e2e: {
                options: {
                    configFile: '<%= yeoman.test %>/protractor.conf.js', // Target-specific config file
                    args: {} // Target-specific arguments
                }
            }
        },

        shell: {
            webdriver: {
                options: {
                    stdout: true
                },

                command: 'phantomjs --webdriver=4445'
            }
        },

        htmlSnapshot: {
            all: {
                options: {
                    //that's the path where the snapshots should be placed
                    //it's empty by default which means they will go into the directory
                    //where your Gruntfile.js is placed
                    snapshotPath: 'snapshots/',
                    //This should be either the base path to your index.html file
                    //or your base URL. Currently the task does not use it's own
                    //webserver. So if your site needs a webserver to be fully
                    //functional configure it here.
                    sitePath: 'http://localhost:9000',
                    //you can choose a prefix for your snapshots
                    //by default it's 'snapshot_'
                    fileNamePrefix: 'sp_',
                    //by default the task waits 500ms before fetching the html.
                    //this is to give the page enough time to to assemble itself.
                    //if your page needs more time, tweak here.
                    msWaitForPages: 1000,
                    //sanitize function to be used for filenames. Converts '#!/' to '_' as default
                    //has a filename argument, must have a return that is a sanitized string
                    sanitize: function (requestUri) {
                        //returns 'index.html' if the url is '/', otherwise a prefix
                        if (/\//.test(requestUri)) {
                            return 'index.html';
                        } else {
                            return requestUri.replace(/\//g, 'prefix-');
                        }
                    },
                    //if you would rather not keep the script tags in the html snapshots
                    //set `removeScripts` to true. It's false by default
                    removeScripts: false,
                    //set `removeLinkTags` to true. It's false by default
                    removeLinkTags: false,
                    //set `removeMetaTags` to true. It's false by default
                    removeMetaTags: false,
                    //Replace arbitrary parts of the html
                    replaceStrings: [
                        {'this': 'will get replaced by this'},
                        {'/old/path/': '/new/path'}
                    ],
                    // allow to add a custom attribute to the body
                    bodyAttr: 'data-prerendered',
                    //here goes the list of all urls that should be fetched
                    urls: [
                        '',
                        '#!/en-gb/showcase'
                    ],
                    // a list of cookies to be put into the phantomjs cookies jar for the visited page
                    cookies: [
                        {'path': '/', 'domain': 'localhost', 'name': 'lang', 'value': 'en-gb'}
                    ]
                }
            }
        }
    });


    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'bowerInstall',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload'
        ]);
    });

    grunt.registerTask('server', function () {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve']);
    });

    grunt.registerTask('test', [
        'clean:server',
        'concurrent:test',
        'autoprefixer',
        'connect:test',
        'karma'
        //'protractor'
    ]);

    grunt.registerTask('build', [
        'newer:jshint',
        'clean:dist',
        'bowerInstall',
        'sass:dist',
        'useminPrepare',
        'copy:styles',
        //'imagemin', // Removed From Build Process - Bamboo problems TODO: Fix this
        'svgmin',
        'autoprefixer',
        'concat',
        'copy:dist',
        'ngAnnotate',
        //'cdnify',  //Do we need this - if so we need to install it
        'cssmin',
        'uglify',
        'rev',
        'usemin',
        'htmlmin'

    ]);

    grunt.registerTask('bamboo', [
        'clean',
        'newer:jshint',
        'karma'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};

那么你需要做的就是从命令行运行:

$ root-of-your-app-where-Gruntfile-lives/grunt karma

【讨论】:

  • 如果它也有帮助,我可以添加一些示例控制器/单元测试文件,但如果我这样做了,我会超出分配给这个答案的正文长度!希望这在某种程度上有所帮助!
  • 非常感谢,您帮了大忙!我仍然在做正确的事情,但你已经为我指明了正确的方向,一切都在按应有的方式进行。
猜你喜欢
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
相关资源
最近更新 更多