Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 模拟/存根仅在闭包中定义的对象_Javascript_Unit Testing_Ecmascript 6_Mocha.js_Chai - Fatal编程技术网

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

Javascript 模拟/存根仅在闭包中定义的对象,javascript,unit-testing,ecmascript-6,mocha.js,chai,Javascript,Unit Testing,Ecmascript 6,Mocha.js,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) ...

首先,为了测试我的库,我正在使用摩卡和柴,但我可能也会在某个时候需要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;
这基本上就是测试文件:

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

describe('MyLib', () => {
    describe('a method that uses the service', () => {
        ...
服务
对象对远程服务器进行了一些调用,这在测试中是无法实现的。因此,我认为应该存根服务的方法或模拟整个服务对象。但是,由于对象是常量,并且只能通过
MyLib
闭包访问,因此我不知道如何访问

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

如果重要的话,我会将Babel 6与es2015预设一起使用


我应该如何处理这个问题?

您对
MyLib
的测试不应该测试
服务
,因此我建议对其全部或大部分进行模拟。您应该检查
MyLib
是否使用正确的参数在
service
上调用了正确的函数


我对sinon不太清楚,但这看起来是导入和使用库的一种非常标准的方式,如果它不支持mocking
服务,我会感到惊讶。有几种方法可以做到这一点

没有额外库的最简单方法 将服务另存为类属性并从中调用:

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;
然后,您可以在测试中重写服务实例:

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
});
Mock require()函数 有些库允许您重写
require()
函数的结果。我最喜欢的是。您可以使用它,您的模块将获得mockedSerice而不是real:

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
});
使用
重新布线
进入模块闭合区 是一个特殊的库,用于插入模块代码,以便您可以在其中更改任何局部变量

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
});
此外,还有一个更好地与您的工具集成的方法


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

我最近也在处理同样的问题。 你可以利用 在您正在编写的测试中,要求/导入服务的方式与您在测试文件中所做的方式相同。 然后使用Sinon在要测试的文件中存根您正在使用的方法

sinon.stub(Service, put).returns()
当文件需要服务时,它将使用修改后的模块


我还没有测试过您的具体案例,您正在创建服务实例,并且只有在使用它之后,才可以使用它,但是稍微玩玩一下它应该可以帮助您实现您想要的,而且它没有任何外部库,只有简单的sinon存根。

我同意您建议的方法,但问题是,
服务
只能通过
MyLib
访问,因为它们共享相同的闭包。因此,我不知道如何存根/模拟它。我假设您使用的是Babel,因为这是ES2015语法。看起来sinon不支持这样的模拟依赖项,您可能需要填充模拟。我在babel号角追踪器上读到了关于sinon的信息,这让我想到了。是的,我在es2015预设中使用了babel。我将把这一点添加到帖子中。基本上,
babel-plugin-rewire
应该让你用其他东西来代替
service
,而不是用mock来修补
service
,在本例中,是一个mock对象。这是一个微妙的区别,但由于您导入的是
服务
而不是注入依赖项,因此您需要替换从“服务”导入的
import*带来的内容
,您可以尝试通过这一点来模拟您的
服务
,这是一个全面而令人敬畏的过程。我很欣赏您分享的所有技术,因为我可以从第一种方法开始测试以简化测试,然后迁移到其他方法以获得更好的编码风格