【问题标题】:Karma-webpack: Unknown provider: LeaveServiceProvider <- LeaveServiceKarma-webpack:未知提供者:LeaveServiceProvider <- LeaveService
【发布时间】:2017-06-01 09:56:39
【问题描述】:

我的应用程序运行良好,但我无法运行测试

$ 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 (evaluating '$httpBackend.expectPOST'

【问题讨论】:

  • 我在控制器单元测试中不正确地注入角度服务时遇到了这个问题。您确定 $httpBackend 已正确注入您的 LeaveService 吗?看到错误,您的问题来自您的测试,而不是您的配置。
  • 我同意,但测试在使用前正在运行。您能详细说明一下注入问题吗?

标签: angularjs testing webpack karma-runner karma-webpack


【解决方案1】:

当 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 方法。

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

【讨论】:

  • 感谢关于注入的召回,但模拟我想测试的服务不是一个好主意。
【解决方案2】:

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

  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. karma.conf.js中加载构建的appangular-mocktest/**/*.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']
    });
};

【讨论】:

  • 你的webpack.conf.jssn-p 和karma.conf.js一样
猜你喜欢
  • 1970-01-01
  • 2013-07-07
  • 2013-09-27
  • 2016-11-29
  • 2018-09-28
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多