【发布时间】:2020-12-04 02:32:10
【问题描述】:
在观看了this example 如何使用它来测试 React 应用程序中的 API 调用之后,我开始使用 msw (mock service worker)。
我们有什么办法可以监视模拟服务工作者?
例如:
import React from 'react'
import { render, act, await } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import SearchBox from '.'
const fakeServer = setupServer(
rest.get(
'https://api.flickr.com/services/rest/?method=flickr.photos.search',
(req, res, ctx) => res(ctx.status(200), ctx.json({ data: { photos: { photo: [] },},}))
)
)
beforeAll(() => {fakeServer.listen()})
afterEach(() => {fakeServer.resetHandlers()})
afterAll(() => fakeServer.close())
test('it calls Flickr REST request when submitting search term', async () => {
const { getByLabelText } = render(<SearchBox />)
const input = getByLabelText('Search Flickr')
const submitButton = getByLabelText('Submit search')
await act(async () => {
await userEvent.type(input,'Finding Wally')
await userEvent.click(submitButton)
})
await wait()
// TODO: assert that the fakeServer was called once and with the correct URL
})
要测试的组件如下所示:
import React, { useState } from 'react'
import axios from 'axios'
import './index.css'
function SearchBox({ setPhotos }) {
const [searchTerm, setSearchTerm] = useState('')
const handleTyping = (event) => {
event.preventDefault()
setSearchTerm(event.currentTarget.value)
}
const handleSubmit = async (event) => {
event.preventDefault()
try {
const restURL = `https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=${
process.env.REACT_APP_API_KEY
}&per_page=10&format=json&nojsoncallback=1'&text=${encodeURIComponent(
searchTerm
)}`
const { data } = await axios.get(restURL)
const fetchedPhotos = data.photos.photo
setPhotos(fetchedPhotos)
} catch (error) {
console.error(error)
}
}
return (
<section style={styles.container}>
<form action="" method="" style={styles.form}>
<input
aria-label="Search Flickr"
style={styles.input}
value={searchTerm}
onChange={handleTyping}
/>
<button
aria-label="Submit search"
style={styles.button}
onClick={handleSubmit}
>
SEARCH
</button>
</form>
</section>
)
}
我有一个工作测试,但我觉得它倾向于实施测试,因为它使用了setPhotos 上的间谍
test('it calls Flickr REST request when submitting search term', async () => {
const fakeSetPhotos = jest.fn(() => {})
const { getByLabelText } = render(<SearchBox setPhotos={fakeSetPhotos} />)
const input = getByLabelText('Search Flickr')
const submitButton = getByLabelText('Submit search')
await act(async () => {
await userEvent.type(input, 'Finding Walley')
await userEvent.click(submitButton)
})
await wait()
expect(fakeSetPhotos).toHaveBeenCalledWith([1, 2, 3])
})
【问题讨论】:
-
为什么你认为 setPhotos 是一个测试替身,表示实现测试?回调 prop 是组件期望的行为的一部分。
-
我正在传递一个函数
setPhotos来更新父状态,但可能是我使用了反应上下文而不是它不会作为道具出现。 -
但这将是行为的改变,在这个组件的级别。如果您希望能够在不更改测试的情况下更改父子通信方式,则不应在它们之间的接口处进行测试。请不要在标题中添加标签,这就是标签的用途。
-
但无论如何,这些都与您实际要求的内容没有直接关系,因为这个问题实际上与
setPhotos行为无关,更多的是关于 other 部分组件的行为,想知道它发出了它应该发出的请求。部分问题在于关注点分离 - 如果您将实际的请求提取到协作者,则可以将其替换为简单的测试替身,组件只需为其提供搜索词 (expect(service.getPhotos).toHaveBeenCalledWith(searchInput))。跨度> -
这是一个很好的观点,父母和孩子之间的接口测试很有价值。我还想测试它是否调用了正确的 REST URL。
标签: javascript reactjs unit-testing jestjs