如何在不失败测试的情况下获得 Jest toThrow 的覆盖率
Posted
技术标签:
【中文标题】如何在不失败测试的情况下获得 Jest toThrow 的覆盖率【英文标题】:How to get coverage for Jest toThrow without failing test 【发布时间】:2018-03-22 04:00:04 【问题描述】:假设我正在使用jest --coverage
测试下面的 React 组件:
class MyComponent extends React.Component
constructor(props)
super(props)
if (props.invalid)
throw new Error('invalid')
覆盖报告将显示throw new Error('invalid')
行未被覆盖。由于.not.toThrow()
似乎没有涵盖任何内容,因此我使用酶创建了以下测试:
const wrapper = shallow(
<MyComponent invalid />
)
it('should throw', () =>
function fn()
if (wrapper.instance().props.invalid)
throw new Error('invalid')
expect(fn).toThrow()
)
线路被覆盖!然而,测试本身因encountered a declaration exception
而失败 - 这意味着原始组件抛出了错误(应该如此)?
我用toThrow()
错了吗?
【问题讨论】:
不应该是expect(fn()).toThrow()
@AndreasKöberle no
【参考方案1】:
意识到这是一个老问题,但对于未来的观众,我想我会扩展 @galki 的答案。您可以简单地将 shallow
/mount
包装在匿名函数中,然后使用 .toThrowError()
,而不是使用 try/catch:
const TestComponent = () =>
throw new Error('Test error');
describe('Test Component', () =>
it('Throws an error', () =>
expect(() => shallow(<TestComponent />)).toThrowError();
);
);
这为您提供更简洁的代码,但结果相同。
【讨论】:
这也适用于无状态:expect(() => shallow(TestComponent())).toThrowError();
【参考方案2】:
显然这与how React 16 handles errors 相关联。我设法通过使用具有 componentDidCatch
方法的父 React 组件包装 MyComponent
来通过测试。
这使测试通过但为了影响覆盖率,我不得不将shallow
更改为mount
。测试最终看起来像这样:
class ParentComponent extends React.Component
componentDidCatch(error)
// console.log(error)
render()
return this.props.children
class MyComponent extends React.Component
constructor(props)
super(props)
if (props.invalid)
throw new Error('invalid')
const wrapper = mount(
<ParentComponent>
<MyComponent invalid />
</ParentComponent>
)
it('should throw', () =>
function fn()
if (wrapper.props().invalid)
throw new Error('invalid test')
expect(fn).toThrow()
)
更新
在意识到问题是在shallow
或mount
中抛出错误后(在测试之前),我将整个事情简化为:
class MyComponent extends React.Component
constructor(props)
super(props)
if (props.invalid)
throw new Error('invalid')
it('should throw', () =>
let error
try
shallow(<MyComponent invalid />)
catch (e)
error = e
expect(error).toBeInstanceOf(Error)
)
【讨论】:
哇,你救了我,这是正确的。.toThrow()
仅适用于纯函数,如果我们使用渲染器或浅层,则此测试不起作用。
不必使用let
并分配try/catch 的结果,为什么不将shallow()
包装在一个匿名函数中并在其上调用.toThrowError()
?例如。 expect(() => shallow(<TestComponent />)).toThrowError();
【参考方案3】:
galki,我认为问题在于您在 constructuring 组件时抛出错误。它没有通过测试,因为它应该(你完全正确)。 相反,如果您可以在其他地方提取 prop-checking 功能,在安装期间不会调用它 - 它会完美运行。比如我把你的sn-ps修改为
export default class MyComponent extends React.Component
constructor(props)
super(props)
componentWillReceiveProps(nextProps)
if (nextProps.invalid)
throw new Error('invalid')
render()
return (
<div/>
)
和
const wrapper = shallow(
<MyComponent />
)
it('should throw', () =>
function fn()
wrapper.setProps(invalid: true);
;
expect(fn).toThrow();
)
因此,如果您有机会在安装时不抛出错误 - 您将能够对其进行测试。
【讨论】:
componentWillReceiveProps
在这种情况下不会被调用。我喜欢测试组件创建,而不是更新以上是关于如何在不失败测试的情况下获得 Jest toThrow 的覆盖率的主要内容,如果未能解决你的问题,请参考以下文章