简体   繁体   English

"使用 Jasmine 进行单元测试,模拟构造函数"

[英]Unit testing with Jasmine, mocking a constructor

I'm unit testing JavaScript with Jasmine and I am running into some problems.我正在使用 Jasmine 对 JavaScript 进行单元测试,但遇到了一些问题。

I have a large file to test and it has a lot of dependencies and those dependencies have their own dependencies.我有一个大文件要测试,它有很多依赖项,这些依赖项有自己的依赖项。 Because of said dependencies I want to mock all I can.由于上述依赖关系,我想尽我所能模拟。 There lies the problem.这就是问题所在。 How can I mock a constructor so that it includes the methods that belong to it?如何模拟构造函数以使其包含属于它的方法?

Lets say I'm testing a method createMap<\/code> of class Map<\/code> :假设我正在测试类Map<\/code>的方法createMap<\/code> :

In that createMap<\/code> method it calls for Layers<\/code> class constructor using在该createMap<\/code>方法中,它使用调用Layers<\/code>类构造函数

var layers = new Layers()

IMO, it's unnecessary to spy on window , since you can easily shadow the variable in local scope by creating a spy object with the same name: IMO,没有必要监视window ,因为您可以通过创建具有相同名称的间谍对象轻松地在本地范围内隐藏变量

describe('Map', function () {
    var Layers;

    beforeEach(function () {
        Layers = function () {
            // alternatively, you could move this to Layers.prototype
            this.addLayers = jasmine.createSpy('Layers#addLayers');
        };
    });

    /* ... */
});

If you want an automatic mocking and using CommonJS modules, you may try Jest framework, which is built on top of Jasmine. 如果你想要一个自动模拟和使用CommonJS模块,你可以尝试Jest框架,它建立在Jasmine之上。

Let's talk in terms of example classes you have provided. 让我们谈谈您提供的示例类。

You're writing a test suite for Map . 您正在为Map编写测试套件。 All its dependencies (in example we have only Layer ) MUST be mocked. 它的所有依赖项(例如我们只有Layer )必须被模拟。 Because in a unit test you're supposed to test one layer, as small functionality as possible. 因为在单元测试中,您应该测试一个层,尽可能小的功能。 It means that you should provide such a mocked Layer constructor that exposes interface used in Map . 这意味着您应该提供这样一个模拟的Layer构造函数,该构造函数公开Map使用的接口。 For example: 例如:

function Layers() {
    this.addLayer = sinon.spy();
}

In this test suite only Map class should remain "real". 在这个测试套件中,只有Map类应该保持“真实”。 Ie it's code must not be altered. 即它的代码不得更改。 And with such mockups like Layer you make sure that you do not trigger any interaction with real-code dependencies (own-written dependencies should be tested in a different test suite, also make sure you don't try to test framework functions, like $tate.resolve , $inject etc.). 使用像Layer这样的模型,你可以确保不会触发与实际代码依赖的任何交互(自己编写的依赖项应该在不同的测试套件中进行测试,同时确保你不要尝试测试框架函数,比如$tate.resolve$inject等)。 If class Map is complicated and has multiple dependencies, investigate sinon features that help automate this process, for example sinon.mock 如果类Map很复杂且具有多个依赖关系,请调查有助于自动执行此过程的sinon功能,例如sinon.mock

If you ever transpile class syntax to a es3 or another pre-2015 dialect you will discover something interesting.如果您曾经将类语法转换为 es3 或其他 2015 年之前的方言,您会发现一些有趣的东西。

class a {
    constructor(){
        ...
    }
    
    index()
   {
      ...
   }
}

Becomes:变成:

var a = /** @class */ (function () {
    function a() {
        ...
    }
    a.prototype.index = function () {
       ...
    };
    return a;
}());

This same implementation is used by later standards but masked by the 2015 class syntax.稍后的标准使用相同的实现,但被 2015 类语法掩盖。 In other words a.index doesn't exist instead it's defined as a.prototype.index .换句话说, a.index不存在,而是被定义为a.prototype.index Thus you need spyOn(a.prototype, 'index') to spy on it.因此,您需要spyOn(a.prototype, 'index')来监视它。

Change spyOn(Layers, 'addLayer') to spyOn(Layers.prototype, 'addLayer') spyOn(Layers, 'addLayer')更改为spyOn(Layers.prototype, 'addLayer')

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

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