1

我的应用程序就像一个魅力,但我无法运行我的测试

$ yarn test
# node node_modules/karma/bin/karma start ./karma.conf.js --single-run

版本

    "angular-mocks": "~1.5.10",
    "karma-webpack": "^2.0.1",
    "webpack": "^1.14.0",
    "webpack-dev-server": "^1.16.2",

错误

PhantomJS 2.1.1 (Linux 0.0.0) leave API service create(): should create a leave FAILED
        Error: [$injector:unpr] Unknown provider: LeaveServiceProvider <- LeaveService
        http://errors.angularjs.org/1.5.10/$injector/unpr?p0=LeaveServiceProvider%20%3C-%20LeaveService (line 4674)
        static/app.min.js:4674:87
        getService@static/app.min.js:4827:40
        static/app.min.js:4679:49
        getService@static/app.min.js:4827:40
        injectionArgs@static/app.min.js:4852:69
        invoke@static/app.min.js:4874:32
        WorkFn@node_modules/angular-mocks/angular-mocks.js:3130:26
        inject@node_modules/angular-mocks/angular-mocks.js:3100:46
        test/leave.service.tests.js:55:23
        loaded@http://localhost:9876/context.js:151:17
        inject@node_modules/angular-mocks/angular-mocks.js:3097:28
        test/leave.service.tests.js:55:23
        loaded@http://localhost:9876/context.js:151:17
        TypeError: undefined is not an object (evaluating '$httpBackend.expectPOST') in test/leave.service.tests.js (line 64)
        test/leave.service.tests.js:64:16
        loaded@http://localhost:9876/context.js:151:17
        TypeError: undefined is not an object (evaluating '$httpBackend.verifyNoOutstandingExpectation') in test/leave.service.tests.js (line 114)
        test/leave.service.tests.js:114:16
        loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 5 (1 FAILED) (skipped 4) ERROR (0.042 secs / 0.01 secs)

Karma.conf.js

const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');

module.exports = function (config) {
    config.set({
        basePath: './',
        frameworks: ['jasmine', 'mocha', 'chai'],
        files: [
            './static/app.min.js',
            'node_modules/angular-mocks/angular-mocks.js',
            {pattern: 'test/leave.service.tests.js'}
        ],
        preprocessors: {
            'test/leave.service.tests.js': ['webpack']
        },
        webpack: {
            module: webpackConfig.module,
            plugins: webpackConfig.plugins
        },
        webpackMiddleware: {
            stats: 'errors-only'
        },
        notifyReporter: {
            reportEachFailure: true,
            reportSuccess: false
        },
        plugins: [
            'karma-phantomjs-launcher',
            'karma-jasmine',
            'karma-webpack',
            'karma-mocha',
            'karma-chai'
        ],
        browsers: ['PhantomJS']
    });
};

webpack.conf.js

const webpack = require('webpack');
const path = require('path');

module.exports = {
    entry: {
        app: './src2/app.js'
    },
    output: {
        path: path.resolve(__dirname, './static'),
        publicPath: '/static/',
        filename: 'app.min.js'
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
            moment: 'moment'
        })
    ],

    resolve: {
        root: path.resolve('./src2'),
        extensions: ['', '.js']
    },
    module: {
        loaders: [
            {test: /\.css$/, loader: 'style-loader!css-loader'},
            {test: /\.scss$/, loader: 'style-loader!css-loader!sass-loader'},
            {test: /\.html$/, loader: 'html-loader'},
            {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/font-woff'},
            {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/font-woff'},
            {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=application/octet-stream'},
            {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader'},
            {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=8192&mimetype=image/svg+xml'}
        ]
    },
    devServer: {
        port: 8080,
        proxy: {
            '/api': {
                target: {
                    host: '0.0.0.0',
                    protocol: 'http:',
                    port: 8000
                }
            }
        }
    }
};

测试/leave.service.js

var chai = require('chai');
var assert = chai.assert;

describe('leave API service', function () {
    var service;
    var $httpBackend;


    beforeEach(inject(function (_$httpBackend_, LeaveService) {
        $httpBackend = _$httpBackend_;
        service = LeaveService;
    }));

    it('create(): should create a leave', function (done) {
        var foo = 'bar';

        assert.equal(foo, 'bar');
        done();
    });
});

问题

这是怎么回事?

相关:Karma-webpack+angular TypeError: undefined is not an object (evalating '$httpBackend.expectPOST'

4

2 回答 2

0

当 Angular 控制器或服务依赖于另一个 Angular 对象(服务、工厂、常量...)时,注入器将在提供者列表(单例构造函数数组)中查找它。如果没有注入器,或者依赖项不存在,则 Angular 将退出并出现与您所拥有的错误类似的错误(服务 x 没有提供者 xProvider)。这应该通过模拟 Angular 模块并将依赖的服务附加到它(方法 1)来解决,或者使用一个函数实例化您的 LeaveService,该函数返回一个填充有方法的对象作为其依赖项参数,例如

// leave-service.spec.js
...
var FakeHttpService = function() {
  return {
    get: function(url) { return new Promise(); },
    post: function(url, data) { return new Promise(); },
    //...
  };
};
var leaveService = new LeaveService(new FakeHttpService());

接下来,当您执行类似的操作时var res = leaveService.get(url),它应该调用 FakeHttpService get 方法。

您应该阅读$httpBackend 上的 Angular 文档以获取有关使用 $http 服务(方法 1)的测试服务的更多详细信息,并了解注入器在测试环境中的工作方式。

于 2017-01-17T11:54:44.947 回答
0

我回到一个非常简单的测试并逐步增加复杂性,直到它失败。解决方案是:

  1. 注入我的应用angular.mock.module('app')

    beforeEach(angular.mock.module('app'));
    
  2. 注入依赖项angular.mock.inject()

    beforeEach(function () {
        angular.mock.inject(function (_$httpBackend_, _LeaveService_) {
            $httpBackend = _$httpBackend_;
            service = _LeaveService_;
        });
    });
    
  3. 加载内置appangular-mocktest/**/*.jsin karma.conf.js

    files: [
        './static/app.min.js',
        'node_modules/angular-mocks/angular-mocks.js',
        {pattern: 'test/foo.service.tests.js'}
    ]
    

完整代码如下

foo.service.tests.js

var chai = require('chai');
var assert = chai.assert;

describe('leave API service', function () {
    var service;
    var $httpBackend;


    beforeEach(angular.mock.module('app'));

    beforeEach(function () {
        angular.mock.inject(function (_$httpBackend_, _LeaveService_) {
            $httpBackend = _$httpBackend_;
            service = _LeaveService_;
        });
    });

    it('create(): should create a leave', function (done) {
        var foo = 'bar';


        assert.equal(foo, 'bar');
        done();
    });
});

webpack.conf.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');

module.exports = {
        entry: {
                app: './src/app.js'
        },
        output: {
                path: path.resolve(__dirname, './static'),
                publicPath: '/static/',
                filename: '[name]-[hash:8].min.js'
        },
        plugins: [
                new webpack.optimize.ModuleConcatenationPlugin(),
                new webpack.ProvidePlugin({
                        $: 'jquery',
                        jQuery: 'jquery',
                        moment: 'moment',
                        Util: 'exports-loader?Util!bootstrap/js/dist/util'
                }),
                new HtmlWebpackPlugin({
                        template: path.resolve(__dirname, './src', 'index.html'),
                        filename: path.resolve(__dirname, 'index.html'),
                        alwaysWriteToDisk: true
                }),
                new HtmlWebpackHarddiskPlugin()
        ],
        resolve: {alias: {Services: path.resolve(__dirname, 'src/services/')}},
        module: {
                rules: [
                        {test: /\.css$/, use: ['style-loader', 'css-loader']},
                        {test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader']},
                        {test: /\.html$/, use: ['html-loader']},
                        {test: /src.*\.js$/, use: ['ng-annotate-loader']},
                        {test: /\.(png|jpg|jpeg|gif|ico)$/, loader: 'file-loader?name=[name].[ext]'},
                        {test: /\.(woff|woff2|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader'}
                ]
        },
        devServer: {
                port: 8080,
                proxy: {
                        '/api': {target: 'http://0.0.0.0:8000'},
                        '/exports': {target: 'http://0.0.0.0:8000'},
                        '/media': {target: 'http://0.0.0.0:8000'}
                }
        }
};

Karma.con.js

const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');

module.exports = function (config) {
    config.set({
        basePath: './',
        frameworks: ['jasmine', 'mocha', 'chai'],
        files: [
            './static/app.min.js',
            'node_modules/angular-mocks/angular-mocks.js',
            {pattern: 'test/foo.service.tests.js'}
        ],
        preprocessors: {
            'test/foo.service.tests.js': ['webpack']
        },
        webpack: {
            module: webpackConfig.module,
            plugins: webpackConfig.plugins
        },
        webpackMiddleware: {
            stats: 'errors-only'
        },
        notifyReporter: {
            reportEachFailure: true,
            reportSuccess: false
        },
        plugins: [
            'karma-phantomjs-launcher',
            'karma-jasmine',
            'karma-webpack',
            'karma-mocha',
            'karma-chai'
        ],
        browsers: ['PhantomJS']
    });
};
于 2017-01-17T12:56:19.967 回答