javascript - 模拟本地存储,用于测试两种方法的功能/覆盖

标签 javascript node.js unit-testing functional-programming sinon

我有以下代码,它使用按预期工作的本地存储,我想为其创建单元测试,问题是我在此函数中使用本地存储

这是我要测试的功能

open: function(url) {
            var that = this;
            if (!localStorage.getItem(“alert”)) {               
                that_run(url)
                    .then(function(isBlocked) {
                        if (isBlocked) { 
                            that._notify();
                            localStorage.setItem(“alert”, true);
                        } else { 
                            localStorage.setItem(“alert”, true);
                            that._exe(“page”,url)
                        }
                    }).done();
            } else {
                that._exe(“page”,url)
            }
        },

这是有效的测试,但我认为重写窗口是不好的做法,我的问题是我是否可以更好地编写这个测试?

it.only("test for open", function () {
    var url = "http://mytesturl”;
    winlocalStorage.getItem = function(){
        return false;
    };
    var oSimulateSpy = sandbox.spy(exc "_simulate");
    return orun.open(url).then(function(){
        expect(oSimulateSpy.called).to.be.true;
    });
}); 

我看到了这篇文章,它使用了函数式编程 https://stackoverflow.com/a/20153543/6124024 但我认为在这种情况下将本地存储作为参数传递有点矫枉过正,因为这个函数(打开)在很多地方被多次调用......有没有更好/更干净的方法来处理这个问题?

最佳答案

你的挣扎是因为你的代码充满了各种各样的副作用。因为您没有从 this._exethat_run 返回任何值,所以对我来说很明显这些函数也存在副作用。您最好从这些函数返回值或 promise 值,而不是依赖这些函数来更改更多外部状态。

这是一种可能更好的编写模块的方法

// use "wrapper" function that configures this module
export default function(storage) {
  return {
    // other functions ...
    async open (url) {
      if (storage.getItem('alert')) {
        return this._exe('page', url) // make sure _exe returns promise
      }
      else if (await that_run(url)) {
        storage.setItem('alert', true)
        return this.notify() // make sure notify returns Promise
        // or return Promise.resolve()
      }
      else {
        storage.setItem('alert', true)
        return this._exe('page', url)
    }
  }
}

在测试代码中使用您的模块

// import mock storage adapter
const MockStorage = require('./mock-storage');

// create mock storage adapter
const mockStorage = new MockStorage();

// pass mock storage adapter to your module as a config argument
const myModule = require('./my-module')(mockStorage);

// don't forget to reset storage before each test
beforeEach(function() {
  mockStorage.reset();
});

it("test for open", async function () {
  var url = "http://mytesturl";
  mockStorage.set('alert', false);
  let someValue = await myModule.open(url);
  assert.equal(someValue, someExpectation);
  assert.equal(mockStorage.get('alert'), true);
});

模拟存储适配器可能如下所示

export default class MockStorage {
  constructor () {
    this.storage = new Map();
  }
  setItem (key, value) {
    this.storage.set(key, value);
  }
  getItem (key) {
    return this.storage.get(key);
  }
  removeItem (key) {
    this.storage.delete(key);
  }
  clear () {
    this.constructor();
  }
}

然后,当您在生产代码中使用您的模块时,您可以传递真正的localStorage

// use window.localStorage as config argument in production code
const myModule = require('./my-module')(window.localStorage);

关于javascript - 模拟本地存储,用于测试两种方法的功能/覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40465470/

相关文章:

javascript - 如何在javascript中访问存储在项目外部的文件?

javascript - AWS SAM 本地 start-api : Set lambda nodejs 12. x 标志(例如 --experimental-modules)?

javascript - 在 angular2 单元测试中获取 ReadableStream 作为主体模拟 http 后端

javascript - 划分一个typeof数是无穷大?

javascript - 这个应用程序正在使用长轮询?

java - 将nodejs项目导入eclipse IDE

c++ - 使用 Visual Studio C++ 进行单元测试时链接器错误

javascript - AngularJS 单元测试,为什么有用?

javascript - 使用 querySelectorAll 排除标签标签

javascript - 在每次迭代期间迭代和进行异步调用的最佳方法