【问题标题】:How To Unit Test React Component With react-intl, react-router-dom v4 and TypeScript如何使用 react-intl、react-router-dom v4 和 TypeScript 对 React 组件进行单元测试
【发布时间】:2020-05-12 04:07:29
【问题描述】:

我目前正在尝试对 React 类组件中的函数进行单元测试。我已经尝试了所有可以访问实际组件的方法。

应用程序当前设置如下:

<IntlProvider ...>
    <BrowserRouter>
        <App/>
    </BrowserRouter>
</IntlProvider>

我要测试的组件,我们称之为用户,在内部定义为:

<Route
    path="/users"
    render={(routeProps) => {
        return (
            <Users
                {...routeProps}
            />
        );
    }}
/>

用户组件是这样的:

type Props = {...}

type State = {...}

class Users extends Component<Props, State> {

    constructor(props: any) { super(props); }

    componentDidMount() { ... }

    componentWillUnmount() { ... }

    isReadOnly = (): boolean => {
        // determine if read only.
    }

}

export default withRouter(Users)

我正在尝试测试一个名为isReadOnly 的函数。但是,我需要先对组件执行 setState(),然后才能实际调用该函数。

到目前为止我已经尝试过:

const wrapper = shallow(<OrderEntry {...props}/>);

但它会抛出错误:ShallowWrapper::setState() can only be called on class components

我认为这一定是因为BrowserRouter。所以我发现我需要使用MemoryRouter 来解决这个问题。

const wrapper = shallow(<MemoryRouter><Users {...props}/></MemoryRouter>);
const usersInstance = wrapper.find(Users).dive().instance();
usersInstance.setState(state);

这会引发错误:TypeError: Cannot read property 'setState' of null

如果我console.log(wrapper),则输出:ShallowWrapper {}。

我对此有点迷茫......我只需要能够做两件事 - 设置状态和单元测试组件功能之一。

【问题讨论】:

  • 你想模拟什么样的状态?如果它来自 URL,我建议您设置内存路由器,使其位于该路由上。建议测试您的组件用户如何看待它们,而不是触及内部工作原理。这将使您的测试变得脆弱。这是一篇很棒的帖子,为什么不好:kentcdodds.com/blog/testing-implementation-details
  • 虽然 Kent 有他的观点,但我正在测试的功能所涉及的逻辑有许多需要针对业务用例进行测试的场景。我没有检查特定组件的实现是否具有特定的可见子元素等。我想查看组件中的单个函数是否返回 True 或 False。
  • 你的用户组件是类还是函数组件?您是在测试用户(包装组件)的默认导出还是命名导出?
  • 所以我刚刚用用户组件结构的更好细节更新了这个问题。它是一个类组件。我想我不明白你的最后一个问题。我只是想根据我传递给组件的道具来测试 isReadOnly() 函数。
  • Redux 开发人员suggest 导出未连接的组件(在您的情况下为Users)并在测试中使用它。这样,您就可以完全控制传递给渲染实例的道具,并且作为奖励,使用酶的 setState...

标签: reactjs typescript react-router-v4 react-router-dom


【解决方案1】:

Redux docs 建议导出未连接的组件(在您的情况下为Users)并在测试中使用它。这样,您就可以完全控制传递给渲染实例的道具,并且作为奖励,使用酶的setState 没有问题。

比如:

export class Users extends Component<Props, State> {

    componentDidMount() { ... }

    componentWillUnmount() { ... }

    isReadOnly = (): boolean => {
        // determine if read only.
    }
}
export default withRouter(Users);

在测试中:

import {Users} from "./Users";

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 2017-10-30
    • 2018-08-23
    • 1970-01-01
    • 2019-01-15
    • 2017-11-10
    相关资源
    最近更新 更多