【问题标题】:How do I mock "this" when writing a unit test for a React module?在为 React 模块编写单元测试时如何模拟“this”?
【发布时间】:2020-03-05 09:53:20
【问题描述】:

我正在编写一个 React 应用程序,其中 App.js 内部有很多逻辑,将其余组件联系在一起并保持一致的状态。我已经将一些原本在 App.js 中的代码移到了 helpermodule.js 中,并绑定了导入的函数,以便它们可以操作 App 组件的状态。

这是我的设置:

App.js

import helperFunction from './helpermodule'

class App extends Component {
  constructor(props) {
    super(props)

    this.state = { foo: 'bar' }
    this.helperFunction = helperFunction.bind(this)
  }
}

helpermodule.js

function helperFunction() {
  this.setState({
    bar: 'calculated' + this.state.foo,
  })
}

export { helperFunction }

我想为辅助模块中的函数编写一个单元测试。我在 Enzyme 或 Jest 文档中找不到相关部分。目标是查看 helperFunction 对 App 状态的影响。

我已经尝试过这样的事情

test('helperFunction', () => {
  let state = { foo: 'bar' }
  let setState = (obj) => { this.state = obj }

  return expect(helperFunction().bind(this))
    .toBe({
      ...newShift,
      id: 0,
    })
}

但这只会返回一个错误; TypeError: Cannot read property 'state' of undefined。也许我的整个方法都是错误的,所以可以绕过这个问题,但我不确定。

【问题讨论】:

  • helperFunction 上的设置非常脆弱,您总是必须绑定它,特别是绑定到反应组件。这不好。只需将其添加到您的应用程序中。您还将某些组件状态隐藏在另一个文件中。不要这样做。
  • 我同意,但我还没有找到更好的解决方案。我可以将 helperFunction 放在 app.js 中,然后从那里使用它,但是对所有其他 helperFunction 这样做会很快溢出 App.js。

标签: javascript reactjs unit-testing mocking


【解决方案1】:

不要在外部函数中使用 this.setState

helpermodule.js

function helperFunction(stateFoo) {
  return {bar: 'calculated' + stateFoo};
}

export { helperFunction }

然后使用结果在组件中设置状态。也不要在构造函数中设置状态。

import helperFunction from './helpermodule'

class App extends Component {
  constructor(props) {
    super(props)

    this.state = { foo: 'bar', ...helperFunction('bar') }
  }
}

这将使测试更容易,并且总体上是一个更好的结构。

【讨论】:

    【解决方案2】:

    不知道您为什么要遵循这种方法,但为了您的论点,它是如此奇怪且难以遵循和维护。问题是你将this 传递给绑定,而this 没有statesetState 的属性,所以你应该传递一个模拟的this

    这是怎么回事

    describe('helperFunction', () => {
        function helperFunction() {
            // @ts-ignore
            this.setState({
                // @ts-ignore
                bar: 'calculated' + this.state.foo,
            })
        }
    
        it('updates the provided stateHolder', () => {
            const stateHolder = {
                state: { foo: 'bar' },
                // don't use arrow function otherwise it won't react the state via this
                setState(obj: any) {
                    this.state = obj;
                },
            };
    
            const importedHelperFunction = helperFunction.bind(stateHolder);
            importedHelperFunction();
    
            expect(stateHolder.state.foo).toBe('calculatedbar');
        });
    });
    

    【讨论】:

    • 在实际的应用程序中,helperFunction 被传递给应用程序的子组件,以便他们可以修改应用程序的状态。我很乐意用更好的解决方案替换它,但我还没有找到。
    猜你喜欢
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多