【问题标题】:Why does the ordering of it functions matter in this jest test?为什么在这个笑话测试中它的功能顺序很重要?
【发布时间】:2020-04-26 11:22:34
【问题描述】:

我有以下组件...

export default class TextInput extends PureComponent<TextInputProps> {

  private handleOnChange = (event: OnChangeEvent): void => {
    if (!this.props.disabled && this.props.onChange) {
      this.props.onChange(event)
    }
  }

  private handleOnBlur = (event: OnBlurEvent): void => {
    if (!this.props.disabled && this.props.onBlur) {
      this.props.onBlur(event)
    }
  }

  public render(): ReactNode {
    return (
      <Styled.TextInput
        id={this.props.id}
        type={this.props.type}
        onChange={this.handleOnChange}
        onBlur={this.handleOnBlur}
        disabled={this.props.disabled}
      />
    )
  }
}

我正在尝试使用以下测试来测试 handleOnChange 函数...


const mockOnChange = jest.fn((): void => { })
const mockOnBlur = jest.fn((): void => { })

const minHandlerProps ={
  id: 'test',
  type: 'text',
  onChange: mockOnChange,
  onBlur: mockOnBlur,
}

describe('handleOnChange', () => {
  it('Should not call the onChange prop when it\'s been passed and TextInput is disabled', () => {
    const wrapper = shallow(<TextInput {...minHandlerProps} disabled={true} />)
    const instance = wrapper.instance()

    instance.handleOnChange()
    expect(minHandlerProps.onChange).not.toHaveBeenCalled()
  })

  it('Should call the onChange prop when it\'s been passed and TextInput is not disabled', () => {
    const wrapper = shallow(<TextInput {...minHandlerProps} />)
    const instance = wrapper.instance()

    instance.handleOnChange()
    expect(minHandlerProps.onChange).toHaveBeenCalled()
  })
})

测试按此顺序通过,但如果我围绕 should not call the onChange prop 交换顺序,测试将失败。

这是因为在这种情况下,onChange 属性已经在第一个 it() 中被调用了吗?

我应该为此写一个单独的描述吗?

我已经通过控制台记录了道具正在正确传递,并且看起来好像它们是正确的,所以我对这种行为感到茫然。感谢任何可以对此有所了解的人。

【问题讨论】:

  • 因为它们共享每个模拟函数的单个实例。您需要清除模拟的 oneall 的状态(或要发生的 configure),或者为每个测试创建一个新状态。
  • @jonrsharpe 谢谢!我无法将您的评论标记为正确答案,但如果您将其添加为答案,我可以在下面将其标记为正确。

标签: javascript reactjs unit-testing jestjs


【解决方案1】:

通过在 describe 块之外定义模拟函数,您可以在所有测试之间共享每个模拟函数的一个实例。这意味着您会看到来自其他测试的调用,因此您的测试是依赖于顺序的(非常对单元测试不利)。

对此有多种解决方案:

  1. 为每个测试创建一个新实例,例如在beforeEach:

    describe('handleOnChange', () => {
      let minHandlerProps;
      let mockOnBlur;
      let mockOnChange;
    
      beforeEach(() => {
        mockOnChange = jest.fn((): void => { })
        mockOnBlur = jest.fn((): void => { })
    
        minHandlerProps = {
          id: 'test',
          type: 'text',
          onChange: mockOnChange,
          onBlur: mockOnBlur,
        }
      });
    
      ...
    });
    
  2. 使用mockClear 在测试之间显式重置每一项:

    describe('handleOnChange', () => {       
      beforeEach(() => {
        mockOnBlur.mockClear();
        mockOnChange.mockClear();
      });
    
      ...
    });
    
  3. 使用clearAllMocks 在测试之间显式重置所有模拟:

    describe('handleOnChange', () => {       
      beforeEach(() => {
        jest.clearAllMocks();
      });
    
      ...
    });
    
  4. 通过在您的配置中将 clearMocks 设置为 true,让 Jest 重置测试之间的所有模拟。


作为旁注,我建议测试在实例上调用 handleOnChange 会调用模拟函数 prop。这就是实现 - 组件的行为是当Styled.TextInput改变时调用回调,或者更好的是当与那个的一些交互时> 组件发生。模拟这些事件可以减少您与当前实现的耦合。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多