Im 使用 react 钩子并使用 Use State 作为组件状态。在开玩笑地测试组件时,我看到我无法访问状态值并模拟它。
有一堆代码在状态中寻找不同的值。 由于状态不可访问,我无法涵盖完整的代码覆盖率。
请帮助我为以下代码编写测试用例。
const MyComponent = props => {
const [counterSecond, setCounterSecond] = React.useState(8);
const [counterFirst, setCounterFirst] = React.useState(0);
const handleIncrement = () => {
setCounterSecond(counterSecond + 1);
};
const handleDecrement = () => {
setCounterSecond(counterSecond - 1);
};
React.useEffect(() => {
if (counterSecond === 10) {
setCounterSecond(0);
setCounterFirst(1);
}
if (counterSecond === 3) {
setCounterSecond(1);
setCounterFirst(0);
}
if (counterSecond ===9) {
setCounterSecond(2);
setCounterFirst(1);
}
}, [counterSecond]);
return (
<div>
<div onClick={handleIncrement} >Increment</div>
<div onClick={handleDecrement} >Decrement</div>
</div>
);
};
export default MyComponent;
如您所见,代码具有 useEffect,它负责 counterSecond 值的变化。但仅当状态值匹配 8 或 3 或 9 时,才会涵盖内部条件。
您能否指导我编写Jest测试用例以涵盖UserEffect中的内部条件。
1)以及如何模拟任何状态值 2)如何在使用钩子时在Jest中检查状态值
假设您的组件呈现counterFirst
和counterSecond
否则它们的存在没有任何意义。类似的东西
....
return (
<div>
<span test-id="counter">{`${counterFirst}:${counterSecond}`}</span>
<div onClick={handleIncrement} id="inc">Increment</div>
<div onClick={handleDecrement} id="dec">Decrement</div>
</div>
);
然后我们想测试我们的组件。我坚信我们不需要嘲笑或断言国家或任何内部结构。相反,我们需要通过props
进行通信并检查渲染的结果,以检查组件的行为是否符合我们的预期。
因此,测试初始状态可能如下所示:
function getCounter(wrapper) {
return wrapper.find("['test-id'='counter']").text();
}
it('renders 0:8 by default', () => {
const wrapper = mount(<MyComponent />);
expect(getCounter(wrapper)).toEqual('0:8');
});
但是如何处理useEffect
中的代码?如果你有足够新的酶版本,它应该可以工作。我相信。如果没有 - 检查您使用的版本。
并返回测试。直到您的代码示例计数器应该以稍微不典型的方式对增量和减少做出反应。对于 inc:0:8 -> 1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0
(因为对于0:9
和1:3
来说,useEffect
中有适当的逻辑会导致重新渲染)。因此,我们将对其进行测试:
function doInc(wrapper) {
wrapper.find("inc").props().onClick();
}
it('jumps from 0:8 to 1:2 on inc', () => {
const wrapper = mount(<MyComponent />); // 0:8
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('1:2');
});
实际上这里的逻辑应该创建值 cycled(1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0
),所以我会在单个测试用例中对其进行测试。但也许在您的实际组件中它不会循环。
您可能想知道如何为某些特定情况设置初始状态?同样的方式:通过调用props
来模仿点击和其他通信。
function doDec(wrapper) {
wrapper.find("dec").props().onClick();
}
it('increments from 0:5 to 0:6', () => {
const wrapper = mount(<MyComponent />); // 0:8
doDec(wrapper); // 0:7
doDec(wrapper); // 0:6
doDec(wrapper); // 0:5
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('0:6');
});
也许做一些辅助功能是个好主意。
但是直接设置状态会更快吗?是的,会的。但这也会使测试不可靠。比如说,你的示例代码永远不会达到"0:9"。这可能是一个错误,而不是一个目标。我们希望测试能帮助我们意识到这一点。通过直接设置状态,我们永远不会知道存在问题。