3

我正在编写一个 Redux 操作来完成一个单元测试,但是在测试中的模拟函数调用有问题。我相信我已经completeRegistration正确地模拟了,通过导入声明它的模块,然后从模块引用中模拟函数,但是 Jest 说尽管控制台日志语句确认verified.data.success条件是true.

任何想法我做错了什么?谢谢

auth.js

export const verifyEmail = ({
    originalCode,
    confirmCode,
    token
}) => async dispatch => {
    try {
        const body = JSON.stringify({
            originalCode,
            confirmCode,
            registering: true
        });
        const verified = await axios.post("/api/email/verify", body, config);
        if (verified.data.success) {
            console.log("Success!") // logs "Success!"
            completeRegistration(token); // test is to find out if this function gets called
        } else {
            return { msg: "Code did not match, please try again" };
        }
    } catch (err) {
        dispatch({
            type: REGISTER_FAILED
        });
    }
};

auth.test.js

import * as auth from "../../actions/auth";

const originalCompleteReg = auth.completeRegistration;

describe("verifyEmail action", () => {
    let verifyData;
    beforeEach(() => {
        verifyData = {
            originalCode: "1234546",
            confirmCode: "1234546",
            token: "87618g1u8ojb98k3jb12i3kwdbcjwvbbi92ueg29eubv" // fake data :p
        };
        auth.completeRegistration = jest.fn(() => auth.completeRegistration);
        moxios.install();
    });

    afterEach(() => {
        auth.completeRegistration = originalCompleteReg;
        moxios.uninstall();
    });

    it("calls completeRegistration function if successful", async () => {
        moxios.wait(() => {
            const request = moxios.requests.mostRecent();
            request.respondWith({
                status: 200,
                response: { success: true }
            });
        });

        const store = mockStore({ payload: {} });

        await store.dispatch(auth.verifyEmail(verifyData));
        expect(auth.completeRegistration).toBeCalled();
    });
});

输出

verifyEmail action › calls completeRegistration function if successful

    expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0
4

1 回答 1

3

问题是您不是在模拟模块内使用的内部值,completeRegistration而是在模拟导出的值。verifyEmailauth

当你导入一个模块时,你会得到一个引用模块函数的对象。如果您覆盖所需模块中的值,您自己的引用将被覆盖,但实现保留原始引用。

因此,在您的情况下,如果您调用auth.completeRegistration测试文件,您将调用模拟版本。但是当调用auth.verifyEmail(内部调用completeRegistration)时,completeRegistration它引用的不是你覆盖的版本。

我认为您不应该测试您的completeRegistration方法是否被调用(毕竟,这是一个实现细节)。相反,您应该检查您的方法的行为是否符合预期(即行为completeRegistration是否已重定向到另一个页面、执行附加请求、保存 cookie 等)。因此,您将模拟正在使用的 API,completeRegistration而不是方法本身。

话虽如此,如果您想检查completeRegistration是否被调用,您仍然有几个选择。

使用 babel rewire插件

您必须安装插件并将其添加到您的 babel 配置中。完成此操作后,您的测试将如下所示:

import AuthModule from '../../actions/auth';
import * as auth from '../../actions/auth';

describe('verifyEmail action', () => {
    let verifyData;

    beforeEach(() => {
        verifyData = {
            originalCode: '1234546',
            confirmCode: '1234546',
            token: '87618g1u8ojb98k3jb12i3kwdbcjwvbbi92ueg29eubv'
        };
        moxios.install();
    });

    afterEach(() => {
        moxios.uninstall();
    });

    it('calls completeRegistration function if successful', async () => {
        moxios.wait(() => {
            const request = moxios.requests.mostRecent();
            request.respondWith({
                status: 200,
                response: { success: true }
            });
        });

        const mockFn = jest.fn();
        AuthModule.__Rewire__('completeRegistration', mockFn);

        const store = mockStore({ payload: {} });

        await store.dispatch(auth.verifyEmail(verifyData));
        expect(mockFn).toHaveBeenCalled();
        AuthModule.__ResetDependency__('completeRegistration');
    });
});

分离不同文件中的功能

您可以为功能创建一个单独的模块completeRegistration。这样,由于您的auth.js必须导入模块,您将能够使用jest.mock功能模拟模块。

于 2020-05-01T11:47:10.613 回答