如何使用thunk动作对mapDispatchToProps进行单元测试

时间:2017-01-13 11:12:11

标签: javascript redux react-redux sinon redux-thunk

我有以下Redux动作创建者:

export const keyDown = key => (dispatch, getState) => {
    const { modifier } = getState().data;
    dispatch({ type: KEYDOWN, key });
    return handle(modifier, key); // Returns true or false
};

以下连接组件:

export const mapDispatchToProps = dispatch => ({
    onKeyDown: e => {
        if(e.target.tagName === "INPUT") return;
        const handledKey = dispatch(keyDown(e.keyCode));
        if(handledKey) {
            e.preventDefault();
        }
    }
});

我正在尝试编写测试,以确保当dispatch不是keyDown时,使用tagName操作调用"INPUT"。这是我的考验:

import { spy } from "sinon";
import keycode from "keycodes";
import { mapDispatchToProps } from "./connected-component";
import { keyDown } from "./actions";

// Creates a simple Event stub...
const createEvent = (tag, keyCode) => ({
    target: {
        tagName: tag.toUpperCase()
    },
    preventDefault: spy(),
    keyCode
});

it("Dispatches a keyDown event with the specified keyCode if the selected element is not an <input>", () => {
    const dispatch = spy();
    const keyCode = keycode("u");
    mapDispatchToProps(dispatch).onKeyDown(createEvent("div", keyCode));
    // This fails...
    expect(dispatch).to.have.been.calledWith(keyDown(keycode));
});

据推测,这与使用箭头功能有关吗?有什么方法可以确保使用我期望的函数签名调用调度吗?

3 个答案:

答案 0 :(得分:3)

keyDown(keycode)每次都会创建一个新函数,并且每个函数实例都不同,测试用例会按预期失败。

这可以通过记忆keyDown

创建的函数来修复
let cacheKeyDown = {};
export const keyDown = key => cacheKeyDown[key] || cacheKeyDown[key] = (dispatch, getState) => {
    const { modifier } = getState().data;
    dispatch({ type: KEYDOWN, key });
    return handle(modifier, key);
};

通过记忆,使用相同keyDown的{​​{1}}次调用会返回相同的功能。

答案 1 :(得分:3)

最简单的解决方案可能是按照另一个答案(+1)中的建议记住keyDown()。这是一种尝试涵盖所有基础的不同方法......

自从keyDown()导入actions后,我们可以stub 返回的功能 使用dummy调用时keyCode值为import * as actions; keyDown = stub(actions, "keyDown"); keyDown.withArgs(keyCode).returns(dummy);

dispatch

然后,我们的unit tests将使用我们之前设置的dummy来验证dummy。我们知道keyDown()只能由我们的存根keyDown()返回,因此此检查还会验证是否已调用mapDispatchToProps(dispatch).onKeyDown(createEvent("div", keyCode)); expect(dispatch).to.have.been.calledWith(dummy); expect(keyDown).to.have.been.calledWithExactly(keyCode);

<input>

为了彻底,我们应该添加单元测试,以确认当目标是mapDispatchToProps(dispatch).onKeyDown(createEvent("input", keyCode)); expect(dispatch).to.not.have.been.called; expect(keyDown).to.not.have.been.called; 时,键事件分派。

keyDown()

我们还应该通过验证使用正确的键事件和键调用给定的dispatch回调来孤立test expect(dispatch).to.have.been.calledWith({type: actions.KEYDOWN, key: keyCode}); 代码:

var refCompaniesById = firebase.database().ref('companies').child(id);

链接

答案 2 :(得分:2)

正如@DarkKnight所说(获得+1),keyDown正在为每次调用返回一个新函数,因此测试失败,因为keyDown(keyCode)!= keyDown(keyCode)

如果您不想更改keyDown的实际实现,可以在模拟测试中进行模拟:

import * as actions from "./actions";   

spyOn(actions, 'keyDown');  

您可以看到有关如何完成的其他答案: