单元测试依赖于其他 getter 的 Vuex getter
Unit test Vuex getters that depend on other getters
我已经设法测试了与其他代码隔离的 Vuex getter。当 getter 依赖于其他 getter 时,我现在面临一些问题,请参见以下示例:
getters.js
export const getters = {
getFoo(state) => prefix {
return `${prefix}: ${state.name}`;
},
getFancyNames(state, getters) {
return [
getters.getFoo('foo'),
getters.getFoo('bar')
]
}
}
getters.spec.js
import { getters } = './getters';
const state = {
name: 'Whosebug'
};
describe('getFoo', () => {
it('return name with prefix', () => {
expect(getters.getFoo(state)('name')).toBe('name: Whosebug');
});
});
describe('getFancyNames', () => {
// mock getters
const _getters = {
getFoo: getters.getFoo(state)
}
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, _getters)).toEqual([
'foo: Whosebug',
'bar: Whosebug'
]);
});
});
当被测试的 getter 依赖于其他具有参数的 getter 时,这意味着我在模拟中引用了原始 getter.getFoo
,这打破了模拟的想法,因为测试开始相互关联。当 getter 增长时,依赖图有多个级别,这会使测试变得复杂。
也许这是要走的路,只是想检查一下我没有遗漏任何东西...
我同意你的看法,在你的模拟中引用实际的合作者违背了模拟的目的。所以我会直接 return 任何你想让你的合作者 return 的东西。
在你的例子中,不要做这样的事情:
// mock getters
const _getters = {
getFoo: getters.getFoo(state)
}
您只需输入 getters.getFoo(state)
会 return:
const _getters = {
getFoo: 'foobar'
}
如果您有一个 getter 需要一个额外的参数,您只需 return 一个 return 是常量的函数:
const _getters = {
getFoo: x => 'foobar',
}
由于我使用的是 Jest,jest 模拟函数中有一个选项让我们在调用时指定 return 值:
mockReturnValueOnce
或 mockReturnValue
可在此处找到更多信息:https://facebook.github.io/jest/docs/en/mock-functions.html#mock-return-values
使用与问题中相同的代码可以这样解决:
const state = {
name: 'Whosebug'
}
describe('getFancyNames', () => {
const getFoo = jest.fn()
getFoo.mockReturnValueOnce('foo: Whosebug')
getFoo.mockReturnValueOnce('bar: Whosebug')
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, { getFoo })).toEqual([
'foo: Whosebug',
'bar: Whosebug'
])
})
})
我发现的一种更简洁的方法是创建您自己的模拟 getters 对象。仅当 getter
像问题一样使用未更改的 state
时才有效。
const state = {
name: 'Whosebug'
}
describe('getFancyNames', () => {
const mockedGetters = {
...getters, // This can be skipped
getFoo: getters.getFoo(state), // We only overwrite what is needed
};
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, mockedGetters)).toEqual([
'foo: Whosebug',
'bar: Whosebug'
])
})
})
额外
如果您确实需要调用其他 getter 函数,只需将模拟的 getters 对象传递给另一个模拟的 getters 对象即可。听起来比实际情况更糟。
getters.py
export const getters = {
getBar(state) = { // new extra hard part!
return state.bar,
},
getFoo(state, getters) => prefix {
return `${prefix}: ${state.name} with some ${getters.getBar}`;
},
getFancyNames(state, getters) {
return [
getters.getFoo('foo'),
getters.getFoo('bar')
]
}
}
const _mockedGetters = {
...getters, // This can be skipped
getFoo: getters.getFoo(state), // We only overwrite what is needed
};
const mockedGetters = {
.._mockedGetters, // Use the mocked object!
getBar: getters.getBar(state, _mockedGetters), // We only overwrite what is needed
};
// continue down the line as needed!
我已经设法测试了与其他代码隔离的 Vuex getter。当 getter 依赖于其他 getter 时,我现在面临一些问题,请参见以下示例:
getters.js
export const getters = {
getFoo(state) => prefix {
return `${prefix}: ${state.name}`;
},
getFancyNames(state, getters) {
return [
getters.getFoo('foo'),
getters.getFoo('bar')
]
}
}
getters.spec.js
import { getters } = './getters';
const state = {
name: 'Whosebug'
};
describe('getFoo', () => {
it('return name with prefix', () => {
expect(getters.getFoo(state)('name')).toBe('name: Whosebug');
});
});
describe('getFancyNames', () => {
// mock getters
const _getters = {
getFoo: getters.getFoo(state)
}
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, _getters)).toEqual([
'foo: Whosebug',
'bar: Whosebug'
]);
});
});
当被测试的 getter 依赖于其他具有参数的 getter 时,这意味着我在模拟中引用了原始 getter.getFoo
,这打破了模拟的想法,因为测试开始相互关联。当 getter 增长时,依赖图有多个级别,这会使测试变得复杂。
也许这是要走的路,只是想检查一下我没有遗漏任何东西...
我同意你的看法,在你的模拟中引用实际的合作者违背了模拟的目的。所以我会直接 return 任何你想让你的合作者 return 的东西。
在你的例子中,不要做这样的事情:
// mock getters
const _getters = {
getFoo: getters.getFoo(state)
}
您只需输入 getters.getFoo(state)
会 return:
const _getters = {
getFoo: 'foobar'
}
如果您有一个 getter 需要一个额外的参数,您只需 return 一个 return 是常量的函数:
const _getters = {
getFoo: x => 'foobar',
}
由于我使用的是 Jest,jest 模拟函数中有一个选项让我们在调用时指定 return 值:
mockReturnValueOnce
或 mockReturnValue
可在此处找到更多信息:https://facebook.github.io/jest/docs/en/mock-functions.html#mock-return-values
使用与问题中相同的代码可以这样解决:
const state = {
name: 'Whosebug'
}
describe('getFancyNames', () => {
const getFoo = jest.fn()
getFoo.mockReturnValueOnce('foo: Whosebug')
getFoo.mockReturnValueOnce('bar: Whosebug')
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, { getFoo })).toEqual([
'foo: Whosebug',
'bar: Whosebug'
])
})
})
我发现的一种更简洁的方法是创建您自己的模拟 getters 对象。仅当 getter
像问题一样使用未更改的 state
时才有效。
const state = {
name: 'Whosebug'
}
describe('getFancyNames', () => {
const mockedGetters = {
...getters, // This can be skipped
getFoo: getters.getFoo(state), // We only overwrite what is needed
};
it('returns a collection of fancy names', () => {
expect(getters.getFancyNames(state, mockedGetters)).toEqual([
'foo: Whosebug',
'bar: Whosebug'
])
})
})
额外
如果您确实需要调用其他 getter 函数,只需将模拟的 getters 对象传递给另一个模拟的 getters 对象即可。听起来比实际情况更糟。
getters.py
export const getters = {
getBar(state) = { // new extra hard part!
return state.bar,
},
getFoo(state, getters) => prefix {
return `${prefix}: ${state.name} with some ${getters.getBar}`;
},
getFancyNames(state, getters) {
return [
getters.getFoo('foo'),
getters.getFoo('bar')
]
}
}
const _mockedGetters = {
...getters, // This can be skipped
getFoo: getters.getFoo(state), // We only overwrite what is needed
};
const mockedGetters = {
.._mockedGetters, // Use the mocked object!
getBar: getters.getBar(state, _mockedGetters), // We only overwrite what is needed
};
// continue down the line as needed!