与Jasmine一起进行单元测试,嘲笑构造函数

Unit testing with Jasmine, mocking a constructor

本文关键字:构造函数 单元测试 Jasmine 一起      更新时间:2023-09-26

我正在用Jasmine对JavaScript进行单元测试,遇到了一些问题。

我有一个大文件要测试,它有很多依赖项,这些依赖项有自己的依赖项。由于上述依赖关系,我想尽我所能嘲笑。问题就在这里。如何模拟构造函数,使其包含属于它的方法?

假设我正在测试类Map:的方法createMap

createMap方法中,它使用调用Layers类构造函数

var layers = new Layers()

我在用监视它

spyOn(window, 'Layers').and.callThrough()

这很好,但稍后在createMap方法中,它调用layers.addLayer(),其中addLayerLayers类的方法。问题是,因为我模拟了Layers调用,所以它无法识别addLayer方法。

有没有一种方法可以模拟它,使它包括被调用类的所有方法,或者是我唯一的选择,即存根整个Layers类或不模拟它?

或者,处理这件事的好方法是什么?我试过spyOn(Layers, 'addLayer'),但它说找不到方法addLayer

如果这有点令人困惑,我很抱歉。我很难思考该怎么问。

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');
        };
    });
    /* ... */
});

如果你想要一个自动嘲讽并使用CommonJS模块,你可以尝试Jest框架,它是在Jasmine之上构建的。

让我们谈谈您提供的示例类。

您正在为Map编写一个测试套件。它的所有依赖项(在示例中,我们只有Layer(都必须被嘲笑。因为在单元测试中,您应该测试一个层,尽可能小的功能。这意味着您应该提供这样一个模拟的Layer构造函数,以公开Map中使用的接口。例如:

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

在这个测试套件中,只有Map类应该保持"真实"。也就是说,它的代码不能被更改。使用像Layer这样的模型,你可以确保你不会触发任何与真实代码依赖项的交互(自己编写的依赖项应该在不同的测试套件中进行测试,也要确保你不会尝试测试框架函数,如$tate.resolve$inject等(。如果类Map很复杂,有多个依赖项,请研究有助于自动化这一过程的sinon功能,例如sinon.mock

如果您将类语法转换为es3或其他2015年之前的方言,您会发现一些有趣的东西。

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

成为:

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

这个相同的实现被后来的标准所使用,但被2015类语法所掩盖。换句话说,a.index并不存在,而是被定义为a.prototype.index。因此,你需要spyOn(a.prototype, 'index')来监视它。

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