25

假设我有以下组件:

import { mapState } from 'vuex';
import externalDependency from '...';

export default {
  name: 'Foo',
  computed: {
    ...mapState(['bar'])
  },
  watch: {
    bar () {
     externalDependency.doThing(this.bar);
    }
  }
}

测试时,我想确保externalDependency.doThing()调用它bar(来自 vuex 状态),如下所示:

it('should call externalDependency.doThing with bar', () => {
  const wrapper = mount(Foo);
  const spy = jest.spyOn(externalDependency, 'doThing');

  wrapper.setComputed({bar: 'baz'});

  expect(spy).toHaveBeenCalledWith('baz');
});

Vue test-utils 有一个 setComputed 方法,可以让我当前测试它,但我不断收到警告说 setComputed 将很快被删除,我不知道还有什么方法可以测试它:

https://github.com/vuejs/vue-test-utils/issues/331

4

4 回答 4

7

从你试图实现

测试时,我想确保使用 bar (来自 vuex 状态)调用 externalDependency.doThing() ,如下所示:

(这确实是纯粹的单元测试方法),你可以强制改变这个观察者,这基本上是一个函数。如果计算值或数据值发生更改,则无需跟踪观察者是否正在更改 - 让 Vue 处理它。因此,要更改已挂载的 Vue 实例中的观察者,只需将其称为

wrapper.vm.$options.watch.bar.call(wrapper.vm)

bar你的观察者的名字在哪里。这样,您将能够测试您要测试的确切功能。

来自此评论的想法https://github.com/vuejs/vue-test-utils/issues/331#issuecomment-382037200,关于您在问题中提到的 vue-test-utils 问题。

于 2020-09-06T19:04:31.053 回答
2

Vue Test Utils文档指出了一种使用非常简单的 Vuex 存储的不同方法:

import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'

// use a localVue to prevent vuex state from polluting the global Vue instance
const localVue = createLocalVue();
localVue.use(Vuex);

describe('Foo.vue', () => {
  let state;
  let store;

  beforeEach(() => {
    // create a new store for each test to prevent pollution
    state = { bar: 'bar' };
    store = new Vuex.Store({ state });
  })

  it('should call externalDependency.doThing with bar', () => 
  {
    shallowMount(MyComponent, { store, localVue });
    const spy = jest.spyOn(externalDependency, 'doThing');
    // trigger the watch
    state.bar = 'baz';
    expect(spy).toHaveBeenCalledWith('baz');
  });
})
于 2019-11-27T18:18:37.177 回答
0

您可以直接在源(即 VueX)处设置值。所以你的store.js会有这样的东西:

const state = {
  bar: 'foo',
};
const mutations = {
  SET_BAR: (currentState, payload) => {
    currentState.bar = payload;
  },
};
const actions = {
  setBar: ({ commit }, payload) => {
    commit('SET_BAR', payload);
  },
};

export const mainStore = {
  state,
  mutations,
  actions,
};

export default new Vuex.Store(mainStore);

然后在你的component.spec.js中你会这样做:

import { mainStore } from '../store';
import Vuex from 'vuex';

//... describe, and other setup functions
it('should call externalDependency.doThing with bar', async () => {
  const localState = {
    bar: 'foo',
  };
  const localStore = new Vuex.Store({
      ...mainStore,
      state: localState,
  });
  const wrapper = mount(Foo, {
    store: localStore,
  });
  const spy = jest.spyOn(externalDependency, 'doThing');
  localStore.state.bar = 'baz';
  await wrapper.vm.$nextTick();
  expect(spy).toHaveBeenCalledWith('baz');
});

您也可以dispatch('setBar', 'baz')在 store 上调用该方法并让突变正确发生,而不是直接设置状态。

NB为每个挂载重新初始化您的状态很重要(即,要么进行克隆,要么重新声明它)。否则,一个测试可以改变状态,下一个测试将从该脏状态开始,即使包装器被破坏。

于 2019-11-26T11:09:16.740 回答
0

您将需要在 VueX 实例上使用某种 mutator,是的,这确实为测试引入了另一个不相关的单元,但是根据您的测试,包括使用 Vuex,这个概念已经被打破了。

以意想不到的方式修改状态更容易导致与实际使用不同的行为。

于 2019-09-10T14:46:12.637 回答