简体   繁体   English

如何使用 useState 钩子设置初始状态

[英]How to set an initial state using the useState hook

I wrote a functional component using the useState hook, the component itself works fine but I'm having trouble testing it.我使用 useState 钩子编写了一个功能组件,该组件本身工作正常,但我无法对其进行测试。 I don't understand how to create a initial state in my component.我不明白如何在我的组件中创建初始状态。 I've tried multiple ways of mocking useState, none of which worked:我尝试了多种模拟 useState 的方法,但都没有奏效:

describe('<Component/>', () => {
    beforeEach() = > {
        jest.spyOn(Readt, 'useState').mockImplementation( () => React.useState(['test']));
        //Also tried this:
        //React['useState'] = jest.fn().mockImplementation( () => React.useState(['test']));
    }
    it('should match snapshot', () => {
        expect(wrapper).toMatchSnapshot()
    }
}

I've seen this post too but was unable to get it to work for me我也看过这篇文章,但无法让它为我工作

How to set initial state for useState Hook in jest and enzyme? 如何在笑话和酶中为 useState Hook 设置初始状态?

I've also read that your not supposed to mock out useState in your unit test but then how do you set an initial state for your components if you don't mock it out?我还读到你不应该在单元测试中模拟 useState 但是如果你不模拟它,你如何为你的组件设置初始状态?

Thanks.谢谢。

EDIT: In regards to an answer below:编辑:关于下面的答案:

Passing in a prop doesn't change the state I'm trying to test.传入 prop 不会改变我要测试的状态。

I have a button which when clicked (one state) renders an input box which, when the user types in (another state) and presses the okay button (yet another state) creates a button based on the content in the input box.我有一个按钮,当点击(一种状态)时呈现一个输入框,当用户输入(另一种状态)并按下 OK 按钮(另一种状态)时,它会根据输入框中的内容创建一个按钮。

The props which is passed helps renders a list of buttons but it has no control over what the user types into the input box.传递的道具有助于呈现按钮列表,但它无法控制用户在输入框中键入的内容。 I'm trying to set a state in the input box and then simulate the click on the okay button and test that.我试图在输入框中设置一个状态,然后模拟点击 OK 按钮并测试它。 I'm not trying to test reacts native useState functionality.我不是要测试本机 useState 功能的反应。 I'm just trying to use what enzyme already has 'wrapper.setState' but how do I do that with useState?我只是想使用已经有“wrapper.setState”的酶,但我如何使用 useState 做到这一点?

Ideally I'd like to set up my component, set up the state in which the user has typed into the input box and then test to see if the ok button does what it's supposed to do.理想情况下,我想设置我的组件,设置用户在输入框中键入内容的状态,然后测试确定按钮是否执行了它应该执行的操作。 Without simulating all the clicks before that.无需模拟之前的所有点击。

A component's state is internal to it, and this is an essential part of understanding React components.组件的状态在其内部,这是理解 React 组件的重要部分。 Once you "grok" that, you can understand that no test should ever try to change it.一旦你“理解”了它,你就可以理解任何测试都不应该试图改变它。

but then how do you set an initial state for your components?那么你如何为你的组件设置一个初始状态呢?

You pass a value to your useState hook, inside the component .您将一个值传递给组件内部的useState钩子。 Your tests should then test your component using that initial state ... they should just pass in props to change it, the same way as your non-test code would.然后,您的测试应该使用该初始状态测试您的组件……他们应该只传入props来更改它,就像您的非测试代码一样。

In fact, even if you somehow could change your initial state (which is impossible AFAIK), your test code should NEVER do anything non-test code does (except to set up testing environments which simulate real ones), since the entire point of making tests is to verify that your non-test code works.事实上,即使你能以某种方式改变你的初始状态(这是不可能的 AFAIK),你的测试代码也不应该做任何非测试代码所做的事情(除了设置模拟真实环境的测试环境),因为整个过程测试是为了验证您的非测试代码是否有效。

Similarly, you never want to test the internals of anything you're testing, whether it's a React component or anything else.同样,您永远不想测试您正在测试的任何东西的内部结构,无论是 React 组件还是其他任何东西。

If you do that, every test you write will break the moment any of those internals change, and a HUGE part of the value of tests is that they let you refactor more easily ( if you don't test internals).如果你这样做,你编写的每个测试都会在这些内部发生任何变化的那一刻中断,而测试的一个重要价值在于它们让你更容易重构(如果测试内部)。 Instead, you want to use your testing tools to measure the output of your component (ie. what HTML it generates).相反,您希望使用您的测试工具来衡量您的组件的输出(即它生成的 HTML)。

And again, this really isn't even about React.再说一次,这甚至与 React 无关。 Good software tests of anything don't try and mess with that thing's internals, either to change or measure them.任何东西的良好软件测试不会试图弄乱那个东西的内部结构,无论是改变还是衡量它们。 Instead, good tests focus on the externals , because again that's all non-test code every works with, and because conceptually everything you test should be a "black box" to your test code.取而代之的是,好的测试侧重于externals ,因为同样是所有非测试代码都可以使用,并且因为从概念上讲,您测试的所有内容都应该是测试代码的“黑匣子”。

EDIT: Response to comment/question edit编辑:回复评论/问题编辑

Your edit doesn't really change my answer to be honest, except that it reminded me Enzyme does have a way to change state in tests (never using it myself I forgot it existed).老实说,您的编辑并没有真正改变我的答案,只是它提醒我 Enzyme 确实有一种方法可以改变测试中的状态(我自己从来没有使用过,我忘记了它的存在)。

But again, just because something is possible doesn't mean it's a good idea, and again, you want to test the exterior of anything you test (not just React components).但同样,仅仅因为某些事情是可能的并不意味着它是一个好主意,并且再次强调,您想测试您测试的任何东西外观(不仅仅是 React 组件)。 The state of a React component is like a variable inside a function: it's internal to that function/component, and something you should avoid testing directly . React 组件的状态就像函数内部的变量:它是该函数/组件的内部变量,您应该避免直接测试。

What you want to test instead is the exterior piece, and (based on your edit) it seems that isn't props ... but it's still something exterior: the DOM.您想要测试的是外部部件,并且(根据您的编辑)它似乎不是props ……但它仍然是外部的东西:DOM。

So what I would instead recommend doing is (again) the same thing the non-test code is doing: "clicking" on your buttons.所以我建议做的是(再次)非测试代码正在做的事情:“点击”你的按钮。 Enzyme makes this very easy with its "simulate" method ( https://airbnb.io/enzyme/docs/api/ReactWrapper/simulate.html ). Enzyme 通过其“模拟”方法 ( https://airbnb.io/enzyme/docs/api/ReactWrapper/simulate.html ) 使这变得非常容易。

If you just simulate the button sequence that creates the state you want, you'll only be testing externals (ie. testing your code the same way it will be used in production), but you will be able to test whatever circumstances you want.如果您只是模拟创建您想要的状态的按钮序列,您将只测试外部(即测试您的代码将在生产中使用的相同方式),但您将能够测试您想要的任何情况。

How about setting a value depending on the environment?如何根据环境设置一个值? Jest sets the environment variable NODE_ENV to 'test': Jest 将环境变量NODE_ENV为“test”:

const inTest = process.env.NODE_ENV === 'test'

[value, setValue] = useState(inTest ? mockValue : defaultValue)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM