如何模拟ES6单元测试的依赖关系? [英] How to mock dependencies for ES6 unit tests?

查看:97
本文介绍了如何模拟ES6单元测试的依赖关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些要转换为ES6的ES5示例项目:

I have some ES5 example project that I would like to convert to ES6:

https://github.com/stefaneidelloth/testDemoES5

https://github.com/stefaneidelloth/testDemoES6

示例包括从类Baa继承的类Qux.

The examples include a class Qux which inherits from a class Baa.

在测试Qux时,我想模拟Baa .

When testing Qux, I would like to mock Baa.

对于 ES5 ,我使用 Squire.js 来模拟AMD模块依赖性,并且单元测试工作正常.

For ES5 I use Squire.js to mock AMD module dependencies and the unit tests work just fine.

不幸的是,我找不到直接支持ES6(="ESMAScript 2015 Language",ES2015)模块的测试框架.我们现在有2020年,并且ES2015还没有单元测试?我已经花了很多时间尝试使这些测试正常工作……并且我的印象是我的方法缺少某些东西.

Unfortunately I could not find a testing framework that supports ES6 (="ECMAScript 2015 Language", ES2015) modules directly. We now have 2020 and there are still no unit tests for ES2015? I already spend a lot of time trying to get these tests working ... and I have the impression that my approach is missing something.

由于找不到直接对ES6测试的支持,因此我尝试坚持使用业力,并使用webpack将ES6模块代码转换为ES5 AMD模块进行测试.

Since I could not find direct support for ES6 tests, I try to stick to karma and use webpack to translate the ES6 module code to ES5 AMD modules for testing.

首先让我们考虑将业力与已转换为AMD模块的requirejs和ES6代码结合使用.

Lets first consider to use karma in combination with requirejs and ES6 code that has been translated to AMD modules.

A..如果我尝试使用 Squire 模拟翻译的类Baa(模块'src/baa'),则此方法不再起作用. Webpack将所有依赖项放在一个文件中,当使用'src/qux'时,不考虑我注入的'src/baa'.

A. If I try to mock a translated class Baa (module 'src/baa') with Squire ... that does not work any more. Webpack puts all dependencies in a single file and when using 'src/qux', my injected 'src/baa' is not considered.

qux.test.js:

define([
    'squire'
], function (
    Squire
) { 

    describe('Qux', function(){

        var sut;        

        beforeEach(function(done){  

            var injector = new Squire();            
            injector.mock('src/baa', createBaaMock());

            injector.require([
                'src/qux'
            ], function(
                quxModule
            ){          
                var Qux = quxModule.default;    
                sut = new Qux('qux');
                done(); 
            }); 

        });

        it('quxMethod', function(){         
            expect(sut.quxMethod()).toEqual('quxMethod');
        }); 

        it('baaMethod', function(){         
            expect(sut.baaMethod()).toEqual('baaMockedMethod');
        }); 

        it('overridableMethod', function(){         
            expect(sut.overridableMethod()).toEqual('qux');
        });     

        function createBaaMock(){
            var BaaMock = function (name) {
                this.name = name;
            };
            BaaMock.prototype.baaMethod = function () {
                return 'baaMockedMethod';
            }

            var moduleMock = {
                default: BaaMock
            }
            return moduleMock;
        }       

    }); 

});

=>我收到错误消息

期望'baaMethod'等于'baaMockedMethod'.

Expected 'baaMethod' to equal 'baaMockedMethod'.

有关调试的更多信息....转换为ES5的缺点是,在调试测试时,浏览器中运行的代码看起来与原始代码不同(默认情况下).因此,可能的错误很难识别.在这里有帮助的是:

Some furhter info on debugging.... The translation to ES5 has the disadvantage that when debugging tests, the code that runs in the browser looks different than the original code (by default). Therefore, possible bugs are harder to identify. What helps here is to:

  • 使用Webpack模式开发"而不是生产"来避免缩小

  • use the webpack mode "development" instead of "production" to avoid minification

启用webpack的 devtool选项以启用源映射.这样,调试时,原始代码也会显示在浏览器中.

enable the devtool option of webpack to enable source mapping. This way, the original code is also shown in the browser when debugging.

B..我尝试使用 inject-loader ,它是Squire.js的替代方法,它了解Webpack: https://github.com/LeanKit-Labs/inject-loader

B. I tried to use inject-loader, an alternative to Squire.js, which knows about webpack: https://github.com/LeanKit-Labs/inject-loader

但是,这似乎是一个CommonJs模块,与我的业力+ requirejs项目不兼容:

However, that seems to be a CommonJs module which is not compatible to my karma + requirejs project:

qux.test.js:

qux.test.js:

describe('Qux', function(){

    var sut;        

    beforeEach(function(done){  

       require(['inject!src/qux'],function(ModuleInjector){
           var quxModule = ModuleInjector({
          'src/baa': crateBaaMock()
        });

        var Qux = quxModule.default;        
        sut = new Qux('qux');

        done(); 
       });

    });

    it('quxMethod', function(){         
        expect(sut.quxMethod()).toEqual('quxMethod');
    }); 

    it('baaMethod', function(){         
        expect(sut.baaMethod()).toEqual('baaMockedMethod');
    }); 

    it('overridableMethod', function(){         
        expect(sut.overridableMethod()).toEqual('qux');
    });     

    function createBaaMock(){
        var BaaMock = function (name) {
            this.name = name;
        };
        BaaMock.prototype.baaMethod = function () {
            return 'baaMockedMethod';
        }

        var moduleMock = {
            default: BaaMock
        }
        return moduleMock;
    }       

}); 

=>我收到错误消息

未捕获的ReferenceError:模块未定义.

Uncaught ReferenceError: module is not defined.

我还尝试了模拟加载器,但没有使其正常工作.

I also tried mock-loader but did not get it working.

C .我尝试不使用AMD模块,而是将CommonJs模块用作Webpack编译的目标.但是,我没有设法同时使用commonjs预处理器和karma的and webpack预处理器.

C. I tried to not use AMD modules but CommonJs modules as target for the webpack compilation. However, I did not manage to use the commonjs proprocessor and the and webpack preprocesser of karma together.

D..我尝试将System.js而不是require.js和webpack与Karma一起使用.但是,karma-system.js依赖于system.js(0.19.47)的一个很旧的版本,我没有使它工作.

D. I tried to use system.js instead of require.js and webpack with Karma. However, karma-system.js relies on a very old version of system.js (0.19.47) and I did not get it working.

E .在对监视默认导出以进行模拟班级.

E. In an answer to a related and old SO question someone suggests to use "import * as obj" style to import a class in form of a module and then spy on the default export to mock the class.

但是,如果多个测试正在使用该修改后的模块"(无法重新定义属性默认"),则可能会导致问题.

However, that might cause issues if several tests are using that "modified module" (the property "default" can not be redefined).

由于webpack不会动态加载依赖项,因此以下测试失败:

Since webpack does not dynamically load dependencies, following test fails:

define([
    'src/baa',
    'src/qux'
],function(
    baaModule,
    quxModule
){

    describe('Qux', function(){

        var sut;        

        beforeEach(function(done){  

            baaModule.default = createBaaMock();

            var Qux = quxModule.default;        
            sut = new Qux('qux');

            done(); 


        });

        it('quxMethod', function(){         
            expect(sut.quxMethod()).toEqual('quxMethod');
        }); 

        it('baaMethod', function(){         
            expect(sut.baaMethod()).toEqual('baaMockedMethod');
        }); 

        it('overridableMethod', function(){         
            expect(sut.overridableMethod()).toEqual('qux');
        });     

        function createBaaMock(){
            var BaaMock = function (name) {
                this.name = name;
            };
            BaaMock.prototype.baaMethod = function () {
                return 'baaMockedMethod';
            }

            var moduleMock = {
                default: BaaMock
            }
            return moduleMock;
        }       

    }); 

}); 


总而言之,我发现了许多过时且不完整的方法来测试ES6模块,但似乎没有一种方法能很好地解决问题.

=> 如果我应该坚持业力,我该如何调整我的测试qux.test.js示例代码(可能还有我的配置文件)以正确模拟类Baa?

=> If I should stay with karma, how do I need to adapt my test qux.test.js example code (and probably my configuration files) to correctly mock the class Baa?

=> 是否可以告诉Webpack 将翻译后的模块分开,以便我可以轻松地使用Squire.js注入依赖项?

=> Is it possible to tell webpack to keep the translated modules separate, so that I can easily inject the dependencies with Squire.js?

=> 在浏览器中是否有更好的,最新的工作流程/框架用于单元测试ES6模块?有人试图将玩笑与业力相结合吗?

=> Is there a better and up to date work flow/framework for unit testing ES6 modules in the browser? Did someone try to combine jest with karma?

相关内容:

  • https://zirho.github.io/2016/06/06/karma-es6/
  • How to mock dependencies for unit tests with ES6 Modules
  • https://www.npmjs.com/package/inject-loader
  • https://github.com/LeanKit-Labs/amd-inject-loader
  • https://jestjs.io/
  • https://www.npmjs.com/package/proxyrequire
  • ES6 unit testing without compilation
  • Webpack: compile folder but keep separate files?
  • https://www.reddit.com/r/javascript/comments/44vngp/es6_webpack_unittesting_i_need_help/
  • How to disable bundling in Webpack for development?
  • Disable Bundling from Webpack
  • https://blog.oharagroup.net/mocking-es2015-imports-in-webpack-2-without-loaders-1dec44365989

推荐答案

我从业力切换为玩笑,在这里是一个正在运行的演示项目:

I switched from karma to jest and here is a working demo project:

https://github.com/stefaneidelloth/testDemoES6Jest

工作流仍然基于转译器(babel),但这是在后台进行的,并不会真正影响开发经验.

The workflow is still based on a transpiler (babel) but that happens in the background and does not really influence the development experience.

模拟某些ES6模块的示例测试代码:

Example test code that mocks some ES6 module:

import Qux from './../src/qux.js';

jest.mock('./../src/baa.js', () => {
    return class BaaMock {
        constructor(name){
            this.name = name;
        }

        baaMethod(){
            return 'baaMockedMethod';
        }
    }   
});

describe('Qux', function(){

    var sut;        

    beforeEach(function(){                  
        sut = new Qux('qux');
    });

    it('quxMethod', function(){         
        expect(sut.quxMethod()).toEqual('quxMethod');
    }); 

    it('baaMethod', function(){         
        expect(sut.baaMethod()).toEqual('baaMockedMethod');
    }); 

    it('overridableMethod', function(){         
        expect(sut.overridableMethod()).toEqual('qux');
    });         

}); 


示例package.json(已启用测试命令的代码覆盖率):


Example package.json (with code coverage enabled for test command):

{
  "name": "testDemoES6Jest",
  "version": "1.0.0",
  "main": "index.js",
  "repository": "https://github.com/stefaneidelloth/testDemoES6Jest.git",
  "author": "Stefan Eidelloth <matameko@posteo.de>",
  "license": "MIT",
  "dependencies": {},
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "babel-jest": "^24.8.0",
    "jest": "^24.8.0",
    "jest-cli": "^24.8.0",
    "requirejs": "2.3.6"
  },
  "scripts": {
    "test": "jest --coverage --collectCoverageFrom src/**/*.js ",
    "debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --watch --runInBand"
  }
}


对于调试,有几种选项,例如:


For debugging there are several options, for example:

a)VisualStudioCode ,以及Jest插件

(Debug =>安装其他调试器=> Jest(将Facebook的Jest带乐趣使用", https://github.com/jest-community/vscode-jest )

(Debug=>Install additional Debuggers=> Jest ("Use Facebook's Jest with Pleasure", https://github.com/jest-community/vscode-jest)

调试配置示例launch.json:

Example debug configuration launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [

        {
            "type": "node",
            "request": "launch",
            "name": "Jest Tests",
            "program": "${workspaceRoot}\\node_modules\\jest\\bin\\jest.js",
            "args": [
                "-i"
            ],           
            "internalConsoleOptions": "openOnSessionStart"           
        }
    ]
}

b)谷歌浏览器:

  • 运行以下控制台命令:
  • Run following console command:

node --inspect-brk ./node_modules/jest/bin/jest.js

node --inspect-brk ./node_modules/jest/bin/jest.js

(可以作为以下脚本中的别名保存在您的packages.json中:{"debug":...并使用 npm run-script debug 运行)

(can be saved as alias within your packages.json under scripts: {"debug": ... and run with npm run-script debug)

  • 打开Chrome浏览器并输入地址

  • Open Chrome browser and enter the address

chrome://inspect

chrome://inspect

  • 单击打开Node专用DevTools

    将项目目录拖放到开发工具中,以允许文件访问(仅需要一次)

    Drag and drop your project directory to the dev tools to allow file access (only required once)

    打开要调试的文件并设置断点

    Open the file you would like to debug and set a break point

    在开发工具中单击继续以继续到所需的断点

    Click continue in the dev tools to continue to your wanted break point

    另请参见

    c)网络风暴

    请参见 https://blog.jetbrains .com/webstorm/2018/10/test-with-jest-in-webstorm/

    有关浏览器中的测试,请参见

    For tests in browsers also see

    https://developers.google.com/web/工具/伪造者/入门

    这篇关于如何模拟ES6单元测试的依赖关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆