React组件测试指南
React是一个在JavaScript开发者社区中取得进展的框架。React为设计组件提供了强大的组合框架。React组件是可以在web应用程序中使用的可重用代码。
React组件与DOM没有紧密耦合,但是它们是否容易进行单元测试呢?在这篇文章中,让我们来探索一下如何对React组件进行单元测试。我将展示使组件可测试的思想过程。
记住,我只是在说单元测试,这是一种特殊的测试。(要了解更多不同类型的测试,我建议您阅读“JavaScript测试:单元测试、功能测试、集成测试”。)
对于单元测试,我感兴趣的是两件事:快速和令人窒息的反馈。有了这个,我可以以高度的信心和代码质量迭代更改。这让你在一定程度上放心,你的React组件不会死在浏览器上。能够快速获得良好的反馈将为您带来竞争优势——在当今敏捷软件开发的世界中,您将希望保持这一优势。
对于演示,让我们做一个类人猿列表,它可以通过复选框过滤。您可以在上面找到整个代码库GitHub.为了简洁起见,我将只展示感兴趣的代码示例。本文假设您对React组件有一定的了解。
如果你下载并运行演示示例代码,你会看到如下页面:
编写可测试组件
在React中,一个好的方法是从组件的层次结构开始。的单一责任原则在构建每个单独的组件时想到的。React组件使用对象组合和关系。
例如,对于类人猿的列表,我有这样的方法:
FilterableGreatApeList |_ GreatApeSearchBar |_ GreatApeList |_ GreatApeRow
看看一个大猿列表是如何包含许多大猿行数据的。React组件使用这个组合数据模型,而且它也是可测试的。
在React组件中,避免使用继承来构建可重用的组件。如果您具有典型的面向对象编程背景,请记住这一点。React组件不会提前知道它们的子组件。测试来自一长串祖先的组件可能是一场噩梦。
我会让你们探索FilterableGreatApeList
靠你自己。这是一个React组件,其中有两个单独的组件。您也可以自由地探索它所附带的单元测试。
建立一个可测试的GreatApeSearchBar
,例如,这样做:
类GreatApeSearchBar扩展组件{构造函数(道具){超级(道具);这.handleShowExtantOnlyChange=这.handleShowExtantOnlyChange.绑定(这);}handleShowExtantOnlyChange(e){这.道具.onShowExtantOnlyInput(e.目标.检查);}渲染(){返回(<形式><输入id="GreatApeSearchBar-showExtantOnly"类型="复选框"检查={这.道具.showExtantOnly}onChange={这.handleShowExtantOnlyChange}/><标签htmlFor="GreatApeSearchBar-showExtantOnly">只显示现存的物种标签>形式>);}}
该组件有一个带有标签的复选框,并连接了一个单击事件。这种方法对您来说可能已经太熟悉了,这是一件非常好的事情。
请注意,使用React,可测试组件是免费的,直接从盒子里拿出来。这里没有什么特别之处——一个事件处理程序、JSX和一个呈现方法。
层次结构中的下一个React组件是GreatApeList
,看起来是这样的:
类GreatApeList扩展组件{渲染(){让行=[];这.道具.猿.forEach((猿)=>{如果(!这.道具.showExtantOnly){行.推(<GreatApeRow关键={猿.的名字}猿={猿}/>);返回;}如果(猿.isExtant){行.推(<GreatApeRow关键={猿.的名字}猿={猿}/>);}});返回(<div>{行}div>);}}
它是一个React组件GreatApeRow
组件,它使用对象组合。这是React最强大的组合模型。请注意,在构建可重用且可测试的组件时缺乏继承。
在程序设计中,对象组合是启用数据驱动元素的设计模式。换个角度想,aGreatApeList
有很多GreatApeRow
对象。UI组件之间的这种关系驱动着设计。React组件内置了这种心态。这种查看UI元素的方式允许您编写一些不错的单元测试。
这里,你检查this.props.showExtantOnly
标记来自复选框的。这showExtantOnly
中的事件处理程序设置GreatApeSearchBar
.
对于单元测试,如何对依赖于其他组件的React组件进行单元测试?那么相互交织的组件呢?在我们即将进入测试阶段时,这些都是需要牢记的重要问题。React组件可能还有可以解锁的秘密。
现在,让我们看一下GreatApeRow
,里面有类人猿的数据:
类GreatApeRow扩展组件{渲染(){返回(<div><img类名称="GreatApeRow-image"src={这.道具.猿.图像}alt={这.道具.猿.的名字}/><p类名称="GreatApeRow-detail"><b>物种:b>{这.道具.猿.的名字}p><p类名称="GreatApeRow-detail"><b>年龄:b>{这.道具.猿.年龄}p>div>);}}
使用React组件,可以将每个UI元素隔离在一个关注点上。当涉及到单元测试时,这具有关键的优势。只要坚持这种设计模式,您就会发现编写单元测试是天衣无缝的。
测试工具
让我们回顾一下测试React组件时最关心的问题。如何单独对单个组件进行单元测试?事实证明,有一个很好的实用工具可以让你做到这一点。
的浅渲染器在React中,你可以在一层深度渲染组件。由此,您可以断言渲染方法所做的事情。值得注意的是它不需要DOM。
使用ES6,你可以这样使用它:
进口ShallowRenderer从“react-test-renderer /浅”;
为了让单元测试快速运行,您需要一种隔离测试组件的方法。通过这种方式,您可以专注于单个问题,测试它,然后转移到下一个关注点。随着解决方案的发展,这变得更加强大,您可以随意重构—保持接近代码,进行快速更改,并确保它可以在浏览器中工作。
这种方法的一个优点是可以更好地考虑代码。这将产生处理手头问题的最佳解决方案。我发现当你不被一大堆分心的事情束缚时,这是一种解放。人类的大脑在一次处理多个问题时表现得很糟糕。
剩下的唯一问题是,这个小工具能让我们用React组件走多远?
把它们放在一起
看一看GreatApeList
例如。你要解决的主要问题是什么?这个组件根据筛选器显示类人猿的列表。
一个有效的单元测试是传入一个列表,并检查关于React组件做什么的事实。我们想确保它能根据标志来过滤类人猿。
一种方法是这样做:
进口GreatApeList从”。/ GreatApeList ';常量猿=[{的名字:“南方古猿”,isExtant:假},{的名字:“猩猩”,isExtant:真正的}];/ /安排常量渲染器=新ShallowRenderer();渲染器.渲染(<GreatApeList猿={猿}showExtantOnly={真正的}/>);/ /行为常量组件=渲染器.getRenderOutput();常量行=组件.道具.孩子们;/ /维护预计(行.长度).托比(1);
注意,我正在使用Jest测试React组件。要了解更多,请查看“如何测试React组件使用笑话”。
在JSX中,看一看showExtantOnly ={真}
.JSX语法允许你设置React组件的状态。这为给定特定状态的组件提供了许多单元测试方法。JSX理解基本的JavaScript类型,因此a真正的
标志被设置为布尔值。
有了这个单子,那GreatApeSearchBar
?的事件处理程序onChange
你可能会感兴趣的东西。
一个好的单元测试是这样做的:
进口GreatApeSearchBar从”。/ GreatApeSearchBar ';/ /安排让showExtantOnly=假;常量onChange=(e)=>{showExtantOnly=e};常量渲染器=新ShallowRenderer();渲染器.渲染(<GreatApeSearchBarshowExtantOnly={真正的}onShowExtantOnlyInput={onChange}/>);/ /行为常量组件=渲染器.getRenderOutput();常量复选框=组件.道具.孩子们[0];复选框.道具.onChange({目标:{检查:真正的}});/ /维护预计(showExtantOnly).托比(真正的);
要处理和测试事件,可以使用相同的浅渲染方法。的getRenderOutput
方法用于将回调函数绑定到带有事件的组件。在这里,onShowExtantOnlyInput
属性被分配回调onChange
函数。
在一个更简单的单元测试中GreatApeRow
反应组件?它使用HTML标记显示类人猿信息。事实证明,您也可以使用浅渲染器来测试这个组件。
例如,让我们确保我们渲染一个图像:
进口GreatApeRow从”。/ GreatApeRow ';常量猿={图像:“https://en.wikipedia.org/wiki/File: Australopithecus_afarensis.JPG”,的名字:“南方古猿”};/ /安排常量渲染器=新ShallowRenderer();渲染器.渲染(<GreatApeRow猿={猿}/>);/ /行为常量组件=渲染器.getRenderOutput();常量apeImage=组件.道具.孩子们[0];/ /维护预计(apeImage).toBeDefined();预计(apeImage.道具.src).托比(猿.图像);预计(apeImage.道具.alt).托比(猿.的名字);
使用React组件,一切都围绕渲染
方法。这使得您可以直观地知道需要测试什么。浅渲染器使得你可以在消除噪音的同时激光聚焦在单个组件上。
结论
如所示,React组件是非常可测试的。没有理由放弃为组件编写好的单元测试。
好在JSX在每个单独的测试中都为您工作,而不是与您作对。使用JSX,您可以传入布尔值、回调值或任何您需要的参数。当你独自进行React组件的单元测试时,请记住这一点。
浅渲染器测试实用程序为您提供了良好的单元测试所需的一切。它只呈现一层深度,并允许您单独测试。您不必担心层次结构中任何可能破坏单元测试的任意子元素。
使用Jest工具,我喜欢它只对正在更改的特定文件提供反馈。这缩短了反馈循环,增加了激光聚焦。我希望你能看到,当你解决一些棘手的问题时,这是多么有价值。