繁体   English   中英

我如何测试方法shouldComponentUpdate?

[英]How do I test the method shouldComponentUpdate?

我想测试方法shouldComponentUpdate但是我写的测试没有发现副作用。 我该如何测试?

我已经尝试了这里提出的解决方案,但是有一些问题将在代码中显示: 如何对React Component应该进行单元测试shouldComponentUpdate方法

我尝试使用shallow而不是mount但是当我这样做时,我的测试此时失败了:

    expect(shouldComponentUpdate).to.have.property("callCount", 1);
    // AssertionError: expected [Function: proxy] to have a property 'callCount' of 1, but got 0

这是我组件的shouldComponentUpdate函数:

    shouldComponentUpdate(nextProps, nextState) {
        if (this.props.storageValue !== nextProps.storageValue) {
            localStorage.setItem(constantFile.storageKey, nextProps.storageValue);
            localStorage.setItem(constantFile.timestampKey, now());
            this.setState({
                newStorage: nextProps.storageValue
            });
            return true;
        }

        ...

        return false;
    }

这是我的测试:

    it("Test shouldComponentUpdate", () => {
        /* eslint-disable one-var */
        const wrapper = mount(
            <Provider store={store}>
                <MyComponent />
            </Provider>),
            shouldComponentUpdate = sinon.spy(CapitalHomeAccessPointContainer.prototype, "shouldComponentUpdate");
        wrapper.setProps({
            storageValue: true
        });
        expect(shouldComponentUpdate).to.have.property("callCount", 1);   
        expect(shouldComponentUpdate.returned(true)).to.be.equal(true);
  expect(localStorage.getItem(constantFile.timestampKey)).to.equal(someExpectedTimestamp);
    });
expect(shouldComponentUpdate).to.have.property("callCount", 1);

失败于

AssertionError: expected false to equal true

为什么会这样? 我以为shouldComponentUpdate应该返回true 稍后,我希望测试状态和本地存储的副作用,但我不理解此错误。

您正在处理shouldComponentUpdate生命周期错误。 您没有在其中设置setState ,而是仅返回一个boolean (true或false)以使React知道何时重新呈现DOM。 这使您可以阻止来自外部道具的更新。 例如:

shouldComponentUpdate(nextProps, nextState) {
 return this.state.newStorage !== nextState.newStorage
}

上面的状态:如果当前newStorage状态与下一个newStorage状态不匹配,则重新渲染该组件。 上面的代码将阻止prop更改重新呈现组件 如果您更改了storage道具,则不会更新该组件,因为状态没有更改。 您要使用shouldComponentUpdate来防止不必要的双重重新渲染和/或防止父组件的重新渲染不必要地重新渲染子组件。 在这种情况下,您将不需要使用此生命周期方法。

相反,您应该使用静态getDerivedStateFromProps来使道具在渲染之前更新状态,或者使用componentDidUpdate在渲染之后更新状态。

在您的情况下,由于您只想在this.props.storageValue更改时更新状态,因此您应该使用componentDidUpdate

componentDidUpdate(prevProps) {
   if (this.props.storageValue !== prevProps.storageValue) {
     localStorage.setItem(constantFile.storageKey, nextProps.storageValue);
     localStorage.setItem(constantFile.timestampKey, now());
     this.setState({ newStorage: nextProps.storageValue });
   }
}

上面的代码检查当前道具是否与以前的道具不匹配,然后更新状态以反映更改。

您将无法使用static getDerivedStateFromProps因为新旧道具之间没有比较,而只有传入的道具与当前状态进行了比较。 也就是说,如果您存储的状态与存储道具直接相关,则可以使用它。 例如,如果您存储了道具中的钥匙并进入状态。 如果props键要更改,并且与状态中的当前键不匹配,则它将更新状态以反映键的更改。 在这种情况下,您将返回一个object以更新状态,或者返回null则不更新状态。

例如:

static getDerivedStateFromProps(props, state) {
  return props.storage.key !== state.storageKey 
  ? { storageKey: props.storage.key }
  : null
}

在测试时,您需要手动更新道具以影响状态更改。 通过针对状态更改进行测试,您将针对componentDidUpdate间接测试。

例如(您必须模拟localStorage ,否则状态将不会更新-我也建议您export class并导入它,而不是使用Redux连接的组件):

import { MyComponent } from "../MyComponent.js";

const initialProps = { storageValue: "" };

describe("Test Component", () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<MyComponent { ...initialProps } />);
  })

  it("updates 'newStorage' state when 'storageValue' props have changed, () => {
    wrapper.setProps({ storageValue: "test" });  
    expect(wrapper.state('NewStorage')).toEqual(...); // this should update NewStorage state

    wrapper.setProps({ someOtherProp: "hello" )};
    expect(wrapper.state('NewStorage')).toEqual(...); // this should not update NewStorage state 
  });
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM