测试实例
快照测试
快照测试是第一次运行测试的时候,在不同情况下的渲染结果保存的一份快照文件,后面每次再运行快照测试时,都会和第一次的比较。
it("test snapshot", () => {
const component = render(<App />);
expect(component.toJSON()).toMatchSnapshot();
});
使用 render 渲染 App 组件,然后匹配 App 组件的片段与快照匹配。
这时候,如果修改 App.js,测试将会失败,因为快照将不再符合条件,可使用 npm test -- -u 更新快照。
测试元素
test('render success', () => {
const { getByText } = render(<Text>描述信息</Text>)
expect(getByText('描述信息')).not.toThrow(/Unable to find an element with text/);
})
说明
渲染一个 Text 文本,通过 getByText('描述信息') 来匹配渲染组件中有无符合 描述信息 的文本元素,如果不能匹配到,则抛出一个错误。
测试事件
// 模拟 onClose 事件
const onClose = jest.fn();
const { getByTestId } = render(<Button onPress={onClose} />);
act(() => {
// 执行 testID 为 button 元素的点击事件
fireEvent.press(getByTestId('button'));
})
// 点击 button 元素后 onClose 方法被调用达到预期效果,测试通过
expect(onClose).toBeCalled();
说明
上例中,我们需要关心的是 Button 组件的点击事件是否被正确调用,这时候需要使用 Mock 函数。
1、使用 jest.fn() 定义一个模拟函数,接着将 onClose 传入示例 Button 组件的点击属性中,接下来是执行这个点击事件。简单来说,这个 fireEvent 接收一个 Dom 节点,并模拟触发 Dom 事件,如:点击、内容更改、滑动等。
2、通过 onClose 函数是否被执行(匹配器 toBeCalled)来判断是否完成对 onClose 方法的测试。
测试异步操作
// 模拟一个数据请求方法
const fetchData = (fn) => {
axios.get('https://api_url/')
.then(response => {
fn(response.data)
})
}
// 使用 done() 方法
// 测试用例会等到 done 方法执行才结束
test('unit test', (done) => {
fetchData((data) => {
expect(data).toMatchObject({
code: 200
})
done();
})
})
我们不能用常规的逻辑去测试异步操作,测试用例不会等到请求结束才执行。所以常规逻辑都会优先与异步操作前执行完。
数据请求返回的是 Promise 对象:
// 数据请求方法
const fetchData = () => {
return axios.get('https://api_url/')
}
// 使用 done() 方法
test('unit test', (done) => {
fetchData().then(res => {
expect(res.data).toMatchObject({
code: 200
})
done();
})
})
// 或者直接使用 return 方法
test('unit test', () => {
return fetchData().then(res => {
expect(res.data).toMatchObject({
code: 200
})
})
})
测试Hook
注意:测试原则上,应避免对组件的 props 或 state 进行断言。
我们使用 @testing-library/react-hooks 来测试 hook,因为测试原则上是对 Dom 和 UI 以及交互事件对 Dom\UI 所带来的影响进行测试,所以我们实际无法拿到定义在组件内部的 props 或者 state。
// ...
import { renderHook } from '@testing-library/react-hooks';
// 构建更改数据的自定义 hook
const useVisibleAction = () => {
const [visible, setVisible] = useState(false);
const update = useCallback((value: boolean) => setVisible(value), []);
return {
update,
value: visible,
}
}
it('unit test', () => {
const { result } = renderHook(useVisibleAction);
const { getByTestId } = render(<Button testID='testID' onPress={value => result.current.update(value)} />);
act(() => {
fireEvent.press(getByTestId('testID'));
})
expect(result.current.value).toBeTruthy();
})
通过构建一个自定义 hook 函数,如代码中的 useVisibleAction,我们定义 update 来执行 setVisible 的方法,并最终将 { update, value: visible } 返回出去。
在 Button 组件中的 onPress 方法中,定义 update 执行,接着通过 fireEvent.press 调用 onPress 方法执行。
最终我们可以模拟 hook 的执行,并通过 result.current.value 获取到执行后的 visible 的值,进行断言,完成测试。
使用时注意点
测试文件
全局安装 jest 依赖:
npm install -g jest-cli
测试单个文件
测试单独的文件,只需要执行 jest demo.test.tsx 命令即可。
注意:执行命令文件匹配,如果执行 jest demo.test.tsx 会匹配所有包含 demo.test.tsx 结尾的测试文件。
如:执行 jest demo.test.tsx 命令,test-demo.test.tsx 、 testdemo.test.tsx 等测试文件均会执行 。
测试全部文件
通过 npm run test 命令来执行脚本对所有测试文件进行测试并监听。
mock 模拟库
mock 模拟 react-native 中标签。
// TouchableHighlight
jest.mock('react-native/Libraries/Components/Touchable/TouchableHighlight', () => 'TouchableHighlight');
// Text
jest.mock('react-native/Libraries/Text/Text', () => 'Text');
mock 模拟 @react-native-clipboard/clipboard 库中方法:setString()、getString()
jest.mock('@react-native-clipboard/clipboard', () => {
let string = undefined;
return {
setString: (text) => string = text,
getString: () => string,
};
});
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理