javascript - 在测试复制实际对象时注入(inject)全局变量,需要相同的实例

标签 javascript mocha.js webpack babeljs

我正在用 mocha、chai 和 sinon 运行测试,主要目的是模拟 localStorage 并将其作为全局变量注入(inject),这样我以后就可以将其称为 localStorage。主要问题是我使用 webpack 和 babel 使用节点策略进行测试(为了更快的测试和开发),所以我使用 rewire 来覆盖全局变量。

这是我的代码:

import assert from 'assert';
import rewire from 'rewire';
import sinon from 'sinon';
import {expect} from 'chai';
import todos from './mocks/todos';
import LocalStorage from './mocks/localStorage.js';
let Todo = rewire('../src/store/todo');


let todo,
    localStorage,
    localStorageMock,
    task = { id: 5, title: 'new task', completed: false };

describe('Todo Model', () => {

  beforeEach(function() {
    localStorage     = new LocalStorage();
    localStorageMock = sinon.mock(localStorage);
    Todo.__set__('globals.localStorage', localStorage);
    todo             = new Todo();
  });

  describe('add todo', () => {
    it('save the todo to localStorage',()  =>{
      localStorageMock.expects('setItem').once();
      todo.create(task);
      localStorageMock.verify();
      expect(localStorage.data['todos']).to.be.a('string');
    });

  });
});

编辑

这是todo模块

import _ from 'ramda';
import {Maybe} from 'ramda-fantasy';

let log = (x, y) => console.log(x, y);

// getItem :: storage, item -> string
let getItem = _.curry((storage, x) => storage.getItem(x));

// parse :: string -> json
let parse = (x) => x ? JSON.parse(x): null;

// stringify :: json -> string
let stringify = (x) => JSON.stringify(x);

// setItem :: storage, string, jsonStringified
let setItem = _.curry((storage, x, y) => storage.setItem(x, y));

export default class todo {

  constructor(){
    this.name = 'name';
    this.storage = localStorage;
    this.storage.getItem('todos') ? '' : this.storage.setItem('todos', '');
  }

  create(todo) {
    this.new = _.compose(_.map(_.compose(setItem(this.storage, 'todos'), stringify, _.append(todo), parse)), Maybe, getItem(this.storage));
    this.new('todos');
  }

}

测试失败,因为 setItem 从未被调用,但在代码中被调用。如果您返回 localStorage 的实例并将其与我的模拟 localStorageMock === returnedLocalStorage 进行比较,则返回 false。

这是因为重新连接复制每个方法分别创建一个新对象。

当我更改 beforeEach block 时:

Todo.__set__('globals.localStorage', localStorage);

Todo.__set__('localStorage', localStorage);

它抛出一个引用错误:

1) Todo Model "before each" hook for "have a create method":
     ReferenceError: localStorage is not defined
      at Function.eval (eval at __set__ (src/store/todo.js:18:26), <anonymous>:1:14)
      at Function.__set__ (src/store/todo.js:18:26)
      at Context.<anonymous> (spec/index.spec.js:18:5)

如何测试是否调用了具有全局依赖性的服务?

最佳答案

我认为问题在于您的 Todo 模块引用了 localStorage,但您正在重新连接 global.localStorage。在rewire README模拟全局变量的示例使用名称 processconsole,而不是 globals.processglobals.console。 Rewire 不够“聪明”(我认为是设计使然),无法知道它们是同一回事。您需要使用模块中使用的确切名称。考虑到这一点,我想你想要的是:

Todo.__set__('localStorage', localStorage);

附言在这种情况下,我认为重新布线可能有点矫枉过正。因为你的模块的构造函数执行 this.storage = localStorage,你可以监视 todo.storage:

todo = new Todo();
sinon.spy(todo.storage, 'setItem');

编辑

认为 ReferenceError 的发生是因为,与示例中的consoleprocess 不同,localStorage 不会已经存在于 Node.js 中。然而,我对 rewire 的了解并不完整,因此可能还有其他答案。

我认为最简单的解决方法是在全局上下文中创建它(也不需要重新布线):

describe('Todo Model', () => {
  beforeEach(function() {
    localStorageMock = sinon.mock(new LocalStorage());
    global.localStorage = localStorageMock; // <-- set it here
    todo = new Todo();
  });

  afterEach(function() {
    delete global.localStorage; // <-- clean up here
  });

  // ...
});

有点丑,但也非常简单。

关于javascript - 在测试复制实际对象时注入(inject)全局变量,需要相同的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33288215/

相关文章:

css - 使用 css 文件设置根元素样式,但不起作用

javascript - AJAX jQuery新版本关于 "Insert into database without page load"

javascript - AJAX/Javascript 在 PHP 中页面加载时选择元素更改

javascript - 在javascript中循环以 append 一系列div

node.js - 如何在 Webstorm 上使用 mocha 运行单元测试?

node.js - 即使将 nodeIntegration 设置为 true,Electron window.require 也不是函数

javascript - DynamoDB 查询有困难

javascript - 使用 mocha js 测试依赖于上一个异步函数的异步函数

node.js - 类型错误 : Cannot read property 'address' of undefined

javascript - 如何使 Chai 打印断言的参数名称而不是它的值