React Native项目中如何在Jest测试用例中覆盖render内的函数?
你当前测试覆盖率不足的核心原因是:仅对App组件做了基础渲染校验,没有处理componentDidMount的异步逻辑,也未覆盖render内的多条件分支,更没有触发传递给子组件的各类回调方法,所以这部分代码未被覆盖率统计命中。
修复步骤
1. 先Mock外部依赖避免干扰
在测试文件开头添加依赖Mock逻辑,隔离子组件和第三方服务的影响,仅聚焦App组件本身的逻辑测试:
// Mock服务层方法 jest.mock('./services/services', () => ({ getData: jest.fn(), hasPermission: jest.fn() })) // Mock所有子组件 jest.mock('../app/components/container/DashboardContainer', () => 'DashboardContainer') jest.mock('../app/components/container/MenuContainer', () => 'MenuContainer') jest.mock('../app/components/ui/digitalFooter', () => 'DigitalFooter') jest.mock('../app/components/container/OffersContainer', () => 'OffersContainer') jest.mock('../app/components/container/DigitalSearchContainer', () => 'DigitalSearchContainer') jest.mock('../app/components/container/BMobileDashboardContainer', () => 'BMobileDashboardContainer') // 异步队列清空工具 const flushPromises = () => new Promise(setImmediate)
2. 覆盖render内opco判断分支
通过MockgetData的返回值,覆盖不同opco下首页组件的渲染逻辑:
test('opco为opco1_rose时渲染BMobileDashboardContainer', async () => { require('./services/services').getData.mockImplementation(key => { if(key === 'opco') return Promise.resolve('opco1_rose') if(key === 'applicationTheme') return Promise.resolve('default') if(key === 'applicationMode') return Promise.resolve('light') return Promise.resolve('') }) require('./services/services').hasPermission.mockResolvedValue(false) const component = renderer.create( <ApolloProvider client={client}> <MockedProvider addTypename={false}> <App navigation={{}} /> </MockedProvider> </ApolloProvider> ) await flushPromises() component.update() expect(component.root.findByType('BMobileDashboardContainer')).toBeTruthy() })
按照同样逻辑再补充2条用例,分别把opco设置为mauritius_telecom和default,即可覆盖另外两个首页渲染分支。
3. 覆盖selectedTab切换分支
直接修改组件实例state切换选中标签,覆盖搜索、优惠、菜单页的渲染逻辑:
test('selectedTab为search时渲染DigitalSearchContainer', async () => { require('./services/services').getData.mockResolvedValue('default') require('./services/services').hasPermission.mockResolvedValue(false) const component = renderer.create( <ApolloProvider client={client}> <MockedProvider addTypename={false}> <App navigation={{}} /> </MockedProvider> </ApolloProvider> ) await flushPromises() // 切换标签到搜索页 component.getInstance().setState({ selectedTab: 'search' }) component.update() expect(component.root.findByType('DigitalSearchContainer')).toBeTruthy() })
按照同样逻辑补充selectedTab为offers、menu的测试用例,即可覆盖剩余标签分支。
4. 覆盖所有未调用的实例方法
触发子组件绑定的回调函数,覆盖方法内部逻辑:
test('所有回调方法逻辑正常', async () => { require('./services/services').getData.mockResolvedValue('default') require('./services/services').hasPermission.mockResolvedValue(false) const component = renderer.create( <ApolloProvider client={client}> <MockedProvider addTypename={false}> <App navigation={{}} /> </MockedProvider> </ApolloProvider> ) await flushPromises() component.update() const instance = component.getInstance() // 测试底部标签切换方法 instance.selectFooterTab('menu') expect(instance.state.selectedTab).toBe('menu') // 测试搜索页显隐方法 instance.showSearchScreen(true) expect(instance.state.showSearchScreen).toBe(true) // 测试底部颜色更新方法 require('./services/services').getData.mockClear() await instance.updateFooterColor() expect(require('./services/services').getData).toHaveBeenCalledTimes(2) // 触发子组件绑定的回调 const footer = component.root.findByType('DigitalFooter') footer.props.selectFooterTab('offers') expect(instance.state.selectedTab).toBe('offers') })
5. 覆盖主题不存在的兜底分支
Mock不存在的主题值,覆盖signatureHeadingColor的空值兜底逻辑:
test('主题不存在时签名色值返回null', async () => { require('./services/services').getData.mockImplementation(key => { if(key === 'applicationTheme') return Promise.resolve('unknownTheme') return Promise.resolve('default') }) require('./services/services').hasPermission.mockResolvedValue(false) const component = renderer.create( <ApolloProvider client={client}> <MockedProvider addTypename={false}> <App navigation={{}} /> </MockedProvider> </ApolloProvider> ) await flushPromises() component.update() const footer = component.root.findByType('DigitalFooter') expect(footer.props.signatureHeadingColor).toBeNull() })
以上用例全部补充完成后,你截图中所有未覆盖的代码都会被命中,测试覆盖率可以达到要求。
内容的提问来源于stack exchange,提问作者Abhigyan Gaurav
相关产品推荐
相关产品推荐

