模拟/存根仅在闭包中定义的对象

dam*_*amd 6 javascript unit-testing mocha.js chai ecmascript-6

首先,为了测试我的库,我正在使用Mocha和Chai,但我有时候也可能需要Sinon.

这是图书馆:

import Service from 'service'; // a third-party module out of my control

const service = Service(...);

class MyLib {
    ... uses `service` in a bunch of different ways ...
    ... service.put(foo) ...
    ... service.get(bar) ...
}

export default MyLib;
Run Code Online (Sandbox Code Playgroud)

这基本上是测试文件:

import MyLib from '../my-lib.js';

describe('MyLib', () => {
    describe('a method that uses the service', () => {
        ...
Run Code Online (Sandbox Code Playgroud)

service对象对远程服务器进行了一些调用,我在测试中无法做到这一点.因此,我认为我应该存根服务的方法或模拟整个服务对象.但是,由于对象是常量并且只能通过MyLib闭包到达,我不知道如何.

理想情况下,我不希望更改API,MyLib例如在构造函数中注入服务对象.

es2015如果重要的话,我会使用预设的Babel 6 .

我该怎么做呢?

jus*_*ris 2

有几种方法可以做到这一点。

最简单的方法,无需额外的库

将服务保存为类属性并从那里调用它:

import Service from 'service'; 

const service = Service(...);

class MyLib {
    constructor() {
       this.service = service;
    }
    ... now you should call service in a bit different way
    ... this.service.put(foo) ...
    ... this.service.get(bar) ...
}

export default MyLib;
Run Code Online (Sandbox Code Playgroud)

然后您可以在测试中重写服务实例:

it('should call my mock', () => {
   const lib = new MyLib();
   lib.service = mockedService; // you need to setup this mock, with Sinon, for example
   lib.doSomething();
   assert.ok(mockedService.put.calledOnce); // works
});
Run Code Online (Sandbox Code Playgroud)

模拟 require() 函数

有一些库允许您覆盖require()函数的结果。我最喜欢的是proxyquire。你可以使用它,你的模块将得到mockedSerice而不是真实的:

import proxyquire from 'proxyquire';

it('should call my mock', () => {
   const MyLib = proxyquire('./my-lib', {
     // pass here the map of mocked imports
     service: mockedService
   })
   const lib = new MyLib();
   lib.doSomething();
   assert.ok(mockedService.put.calledOnce); // works
});
Run Code Online (Sandbox Code Playgroud)

用于rewire访问模块闭包

Rewire是一个特殊的库,用于检测模块代码,以便您可以更改其中的任何局部变量

import rewire from 'rewire';

it('should call my mock', () => {
   const MyLib = rewire('./my-lib')
   const lib = new MyLib();

   // __set__ is a special secret method added by rewire
   MyLib.__set__('service', mockedService);

   lib.doSomething();
   assert.ok(mockedService.put.calledOnce); // works
});
Run Code Online (Sandbox Code Playgroud)

此外,还有babel-plugin-rewire可以更好地与您的工具集成。

以上所有方法都很好,您可以选择更适合您的问题的方法。