react-content-loader测试驱动开发:从测试到实现
react-content-loader测试驱动开发:从测试到实现
你是否还在为组件开发中的边界情况头疼?是否经常在功能上线后才发现隐藏的bug?测试驱动开发(TDD, Test-Driven Development)或许能帮你解决这些问题。本文将以react-content-loader项目为例,带你完整走一遍从测试编写到组件实现的TDD流程,读完你将掌握:
- 如何为React组件设计测试用例
- 如何使用Jest和React Testing Library进行组件测试
- 跨平台组件(Web/Native)的测试策略
- 如何通过测试确保组件属性正确传递
项目概述
react-content-loader是一个基于SVG的React组件,用于轻松创建骨架屏加载效果。项目采用了跨平台设计,同时支持Web和React Native环境。
- 官方文档:README.md
- 核心源码目录:src/
- Web端实现:src/web/ContentLoader.tsx
- React Native实现:src/native/ContentLoader.tsx
TDD开发流程
测试驱动开发遵循"红-绿-重构"(Red-Green-Refactor)的循环:
- 红:编写一个失败的测试
- 绿:编写足够的代码使测试通过
- 重构:优化代码结构而不改变功能
下面我们以ContentLoader组件为例,详细展示TDD流程。
测试用例设计
一个好的测试用例应该覆盖组件的主要功能点和边界情况。在react-content-loader项目中,测试用例主要分为以下几类:
1. 基础渲染测试
验证组件能否正确渲染基本结构。以Web端测试为例:
// [src/web/__tests__/ContentLoader.test.tsx](https://link.gitcode.com/i/d1743878e730073b7dc333f4e63d6fe5)
describe('when type is custom', () => {
const customWrapper = renderer.create(
<ContentLoader>
<rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
<rect x="82" y="44" rx="3" ry="3" width="250" height="10" />
<circle cx="35" cy="35" r="35" />
</ContentLoader>
).root
it('should render custom element', () => {
const rect = customWrapper.findAllByType('rect')
const circle = customWrapper.findAllByType('circle')
expect(rect.length).toBe(3)
expect(circle.length).toBe(1)
})
})
2. 属性传递测试
确保组件的各种属性能够正确传递并生效。测试代码验证了从简单类型到复杂对象的各种属性:
// [src/native/__tests__/ContentLoader.test.tsx](https://link.gitcode.com/i/74965cbaf5f27d922ba99824571e5a86)
describe('Props are propagated', () => {
const withPropsComponent = ShallowRenderer.createRenderer()
withPropsComponent.render(
<ContentLoader
animate={false}
height={200}
preserveAspectRatio="xMaxYMax meet"
backgroundColor="#000"
rtl
foregroundColor="#fff"
speed={10}
style={{ marginBottom: 10 }}
width={200}
beforeMask={<Rect />}
>
<Rect />
</ContentLoader>
)
// 测试各种属性是否正确传递
it("`speed` is a number and it's used", () => {
expect(typeof propsFromFullField.speed).toBe('number')
expect(propsFromFullField.speed).toBe(10)
})
// 更多属性测试...
})
3. 跨平台测试策略
项目同时支持Web和React Native平台,因此需要为不同平台编写相应的测试:
- Web端测试:src/web/tests/
- Native端测试:src/native/tests/
两者的测试结构相似,但针对不同平台的特性做了相应调整。例如,Web端直接使用SVG元素,而Native端使用react-native-svg库提供的组件:
// Web端测试查找原生SVG元素
const rect = customWrapper.findAllByType('rect')
// Native端测试查找react-native-svg组件
const rect = customWrapper.findAllByType(Rect)
组件实现
在编写了测试用例之后,我们来实现ContentLoader组件。根据TDD原则,我们只需要编写足够使测试通过的代码。
基础实现
ContentLoader组件的核心逻辑非常简洁:如果提供了子元素,则渲染自定义加载效果;否则使用默认的Facebook风格加载效果:
// [src/web/ContentLoader.tsx](https://link.gitcode.com/i/91c86120f03d7e66edfa3ca15832a638)
import * as React from 'react'
import { Facebook, IContentLoaderProps } from '.'
import Svg from './Svg'
const ContentLoader: React.FC<IContentLoaderProps> = props =>
props.children ? <Svg {...props} /> : <Facebook {...props} />
export default ContentLoader
预设组件实现
项目提供了多种预设的加载效果,如Facebook风格、Instagram风格等。以Facebook风格为例:
// [src/web/presets/FacebookStyle.tsx](https://link.gitcode.com/i/b578048e718fd48bff99788a4b529c73)
import * as React from 'react'
import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'
const ReactContentLoaderFacebook: React.FC<IContentLoaderProps> = props => (
<ContentLoader viewBox="0 0 476 124" {...props}>
<rect x="48" y="8" width="88" height="6" rx="3" />
<rect x="48" y="26" width="52" height="6" rx="3" />
<rect x="0" y="56" width="410" height="6" rx="3" />
<rect x="0" y="72" width="380" height="6" rx="3" />
<rect x="0" y="88" width="178" height="6" rx="3" />
<circle cx="20" cy="20" r="20" />
</ContentLoader>
)
export default ReactContentLoaderFacebook
测试执行与集成
项目的package.json中定义了完整的测试脚本,方便开发者执行测试:
// [package.json](https://link.gitcode.com/i/2433ac19eca1a8bbeb48f2b6289e12cc)
"scripts": {
"test": "npm run test:tsc && npm run test:unit",
"test:unit": "npm run test:unit:web && npm run test:unit:native",
"test:unit:web": "jest -c jest.web.config.js",
"test:unit:native": "jest -c jest.native.config.js",
"test:watch": "npm run test:unit -- --watch",
"test:tsc": "tsc"
}
执行以下命令可以运行所有测试:
npm test
或者分别运行Web和Native测试:
npm run test:unit:web
npm run test:unit:native
TDD带来的好处
通过react-content-loader项目的TDD实践,我们可以看到以下好处:
- 更可靠的代码:全面的测试覆盖确保了组件在各种情况下的行为符合预期
- 更好的API设计:在实现前先设计测试迫使开发者思考组件的API
- 自信的重构:有了测试保障,可以安全地进行代码重构
- 自动文档:测试用例本身就是组件使用方式的最佳文档
总结
本文通过react-content-loader项目展示了测试驱动开发的完整流程,从测试用例设计到组件实现,再到测试执行与集成。TDD虽然前期会增加一些工作量,但从长远来看,它能显著提高代码质量,减少bug,并使代码更易于维护和扩展。
项目的测试结构清晰,覆盖全面,为我们提供了一个很好的TDD实践范例。无论是Web端还是React Native端的组件,都可以借鉴这种测试思路,构建更健壮的应用。
如果你想深入了解项目的测试实现,可以查看完整的测试代码:
- Web端测试:src/web/tests/
- Native端测试:src/native/tests/
更多推荐

所有评论(0)