简体   繁体   English

单元测试具有外部依赖性的ES6类

[英]Unit Testing ES6 Class with External Dependency

I'm trying to set a unit testing boilerplate for my company. 我正在尝试为我的公司设置单元测试样板。 Our front end projects are built with ES6 classes and have a dependency to our core product. 我们的前端项目使用ES6类构建,并且依赖于我们的核心产品。 The front end code gets wrapped through a build process in a whole other block of code that is basically a closure and captures the dependency. 前端代码通过整个其他代码块中的构建过程进行封装,该代码块基本上是一个闭包并捕获依赖项。 So we don't have to manually import it in order to use it. 因此,我们不必手动导入它以便使用它。

Let's say the dependency is called productScope and it's an object that has some DOM models, internal APIs and parameters among many other things necessary for each project. 假设依赖项称为productScope ,它是一个对象,它包含一些DOM模型,内部API和参数以及每个项目所需的许多其他内容。 At the moment, Mocha throws ReferenceError: productScope is not defined. 目前,Mocha抛出ReferenceError: productScope is not defined. How can I mock this object? 我怎么能模仿这个对象? Or should I just use the actual object? 或者我应该只使用实际的对象?

Example: 例:

class someClass {
    constructor() {
        const id = productScope.items[0].id
        const item = productScope.domModel.querySelector('.some-div')

        item.classList.add(`added-${id}`)
    }
}

This get wrapped in core code like below: 这包含在核心代码中,如下所示:

(function(productScope) {
    // front end code goes here
}(productScope)

Testing file: 测试文件:

import someClass from '../../js/someClass'

describe('someClass', function() {
    const someClass = new someClass()
    it('should be a class', function() {
        console.log(someClass)
    });
});

Looks like productScope is a global variable. 看起来productScope是一个全局变量。

Something like this should work for you. 这样的事情对你有用。

import someClass from '../../js/someClass';

describe('someClass', function() {
    let someClass;

    beforeEach(() => {
        global.productScope = {
          // you mock definition
          someClass = new someClass();
        };
    });

    it('should be a class', function() {
        console.log(someClass)
    });
});

You can try something like this 你可以尝试这样的事情

describe('#someClass', () => {
    let someClass;

    beforeEach(() => {
        global.productScope = {
            // mocking productScope object
        };
    });

    it('should be a class', () => {
        someClass = new SomeClass;
        console.log(someClass);
    });

    afterEach(() => {
        delete global.productScope;
    });
});

or alternatively if you want more specific mock logic for each test case 或者,如果您想为每个测试用例提供更具体的模拟逻辑

describe('#someClass', () => {
    let someClass;

    it('should be a class', () => {
        global.productScope = {
            // mocking productScope object
        };

        // Test logic start

        someClass = new SomeClass;
        console.log(someClass);

        // Test logic end

        delete global.productScope;
    });
});

I'm with other answers as well, as managing global variables seems to be the simplest and most straightforward solution. 我也有其他答案,因为管理global变量似乎是最简单,最直接的解决方案。

However, you can use toString to get class's string representation, and eval it to bind to closure's scope: 但是,您可以使用toString来获取类的字符串表示形式,并将其eval以绑定到closure的作用域:

 class someClass { constructor() { this.id = scopedId } } // pass class as an argument function scopeFactory(classDef) { // define scoped data let scopedId = 2; // eval is used to bind class to the local closure // so `scopedId` will be in charge return eval("(" + classDef + ")"); } const scopedSomeClass = scopeFactory(someClass); console.log(new scopedSomeClass) 

Note that eval(someCLass.toString()) doesn't work without parentheses . 请注意, eval(someCLass.toString()) 在没有括号的情况下不起作用

You can add it as a helper function, into your project. 您可以将它作为辅助函数添加到项目中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM