如何模拟useState挂钩实现,以便在测试过程中实际更改状态 [英] How to mock the useState hook implementation so that it actually changes the state during testing

查看:684
本文介绍了如何模拟useState挂钩实现,以便在测试过程中实际更改状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试测试一个组件,当其内部状态从false更改为true时,该组件将渲染两个不同的子组件:如果为false,则呈现一个按钮,如果按下该按钮,则将状态从false更改为true并呈现另外一个。另一种是在提交时做相反的形式。

I'm trying to test a component which renders two different sub-components when its internal state changes from false to true: when it's false it renders a button that, if pressed, changes the state from false to true and renders the other one. The other is a form that on submit does the opposite.

我试图监视useState挂钩以测试它是否真正被调用。
但是,通过对模块进行模拟,在测试的第二部分中需要实际的setState来测试之后呈现的表单时,它将无法正常工作。

I've tried to spy on the useState hook to test if it's actually called. But by mocking the module, the actual setState won't work when I need it in the second part of the test, to test the form that renders after.

这是我的组件:

import React, { useState } from 'react';

const MyComponent = ({handleChange, handleInput}) => {
     const [state, setState] = useState(false);

     return (
       <div>
         {!state
           ? (
             <button
               data-test="button1"
               type="button"
               onClick={() => setState(true)}
             >
               RenderForm
             </button>
           )
           : (
             <form onSubmit={() => setState(false)}>
               <input type="text" onChange={e => handleChange(e)} />
               <button type="submit">
                 Submit Form
               </button>
               <button type="button" onClick={() => setState(false)}>
                 Go Back
               </button>
             </form>
           )
         }
       </div>
     );
   };
export default MyComponent;

这是我的测试:

import React from 'react';
import { mount } from 'enzyme';
import MyComponent from './MyComponent';


describe('MyComponent', () => {
    let component;

    const mockChange = jest.fn();
    const mockSubmit = jest.fn();
    const setState = jest.fn();
    const useStateSpy = jest.spyOn(React, 'useState');
    useStateSpy.mockImplementation(init => [init, setState]);

    beforeEach(() => {
       component = mount(<MyComponent handleChange={mockChange} handleSubmit={mockSubmit}/>);
    });

    afterEach(() => {
      component.unmount();
    });

    it('calls setState when pressing btn', ()=> {
       component
         .find('[data-test="button1"]')
         .simulate('click')
       expect(setState).toHaveBeenCalledWith(true) // passes
    })
    it('calls handleChange when input changes value', () => {
       component
         .find('[data-test="button1"]') //can't be found
         .simulate('click') 
       component
         .find('input')
         .simulate('change', { target: { value: 'blabla' }}) 
       expect(mockChange).toHaveBeenCalled() // doesn't pass  
  })

  });

我知道问题出在哪里,但我不知道如何解决。有没有办法模拟setState?还是有一种方法可以拆分测试,以免它们彼此干扰?

I know what's the problem, but I don't know how to fix it. Is there a way to mock setState? Or is there a way to split the tests so that they don't interfere with each other?

推荐答案

您可能不应该测试内部实现(例如useState的状态等),但仅测试外部功能(单击按钮更改输出)。

you should probably not test the internal implementation (e.g. the state in useState etc), but only test the external functionality (click on button changes output).

这使测试代码更容易,您实际上测试的是您要测试的内容,而不是测试它是如何实现的,并且如果您更改实现(例如重命名变量),则会得到假否定的答案,因为代码可以正常工作(不关心变量名,并且正确的组件将是呈现),但测试将失败,因为例如您更改了变量的名称。

This make it easier to test your code, you actually test what you want to test and not how it is implemented and if you change the implementation (rename variable for example) you will get a false negative because the code works fine (does not care for variable name and the correct component will be rendered) but your tests will fail, because you changed the name of a variable for example.

这将使以后修改代码的测试更加麻烦。如果您的代码库很大,则想知道代码是否有效,而不想知道代码的实现方式。

This will make it more cumbersome to fix your tests later if you change the code. If you have a large codebase, you want to know if your code works and not how it is implemented.

希望这会有所帮助。祝您编程愉快。

Hope this helps. Happy coding.

这篇关于如何模拟useState挂钩实现,以便在测试过程中实际更改状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆