【问题标题】:Unit testing with Jasmine, mocking a constructor使用 Jasmine 进行单元测试,模拟构造函数
【发布时间】:2015-09-18 12:20:57
【问题描述】:

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

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

假设我正在测试 createMapMap 的方法:

createMap 方法中,它使用

调用 Layers 类构造函数
var layers = new Layers()

我正在使用它来监视它

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

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

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

或者什么是处理这个问题的好方法?我试过spyOn(Layers, 'addLayer'),但它说没有找到方法addLayer

如果有点混乱,我很抱歉。我不知道该怎么问。

【问题讨论】:

  • 要么使用依赖注入,要么使用 Rewire 模块。
  • @limelights 你能多解释一下 Rewire 模块吗?

标签: javascript unit-testing jasmine


【解决方案1】:

IMO,没有必要监视 window,因为您可以通过创建同名的间谍对象轻松地在本地范围内 shadow the variable

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

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

    /* ... */
});

如果您想要自动模拟并使用 CommonJS 模块,您可以尝试构建在 Jasmine 之上的 Jest 框架。

【讨论】:

  • 这听起来像是一个愚蠢的后续问题,但如果我使用这个方法,createMap 方法不会调用var layers = new Layers(),它会失败,因为它是一个对象而不是函数/构造函数。跨度>
  • @MikeJones 你是对的,它需要是一个函数。查看更新的答案。
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-28
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多