【问题标题】:How to get coverage for Jest toThrow without failing test如何在不失败测试的情况下获得 Jest toThrow 的覆盖率
【发布时间】: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

标签: testing jestjs code-coverage enzyme throw


【解决方案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(() =&gt; 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()
})

更新

在意识到问题是在shallowmount 中抛出错误后(在测试之前),我将整个事情简化为:

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(() =&gt; shallow(&lt;TestComponent /&gt;)).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 在这种情况下不会被调用。我喜欢测试组件创建,而不是更新
猜你喜欢
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
  • 1970-01-01
  • 2020-06-03
相关资源
最近更新 更多