有没有办法将参数传递给模拟函数?

时间:2018-12-11 20:08:26

标签: javascript ajax unit-testing jestjs

使用笑话进行单元测试,我有以下内容:

jest.mock('../../requestBuilder');

在我的文件夹中,我有一个

__mocks__
我的模拟requestBuilder.js所在的

子文件夹。我的笑话单元测试正确地正确调用了我的模拟requestBuilder.js。问题是,我的requestBuilder正在模拟ajax返回,因此我希望能够确定是否应该返回成功或失败的服务器响应。理想情况下,我想将参数传递给我的模拟函数,以确定是否“ ajaxSuccess:是/否”。我怎样才能做到这一点?谢谢

1 个答案:

答案 0 :(得分:1)

您不想将参数传递到模拟函数中,传递给模拟函数的参数应由要测试的代码段控制。您要做的是更改模拟函数执行之间的模拟行为。

假设您正在尝试测试以下代码段:

// getStatus.js

const requestBuilder = require('./requestBuilder');

module.exports = () => {
    try {
        const req = requestBuilder('http://fake.com/status').build();
        if (req.ajaxSuccess) {
            return {status: 'success'};
        } else {
            return {status: 'failure'}
        }
    } catch (e) {
        return {status: 'unknown'};
    }
};

我们要测试getStatus是否正确使用requestBuilder,而不是builder.build()方法正常工作。验证builder.build()是一个单独的单元测试的责任。因此,我们为requestBuilder创建了一个模拟,如下所示:

// __mocks__/requestBuilder.js

module.exports = jest.fn();

此模拟只设置了模拟功能,但未实现该行为。模拟的行为应在测试中定义。这将使您在逐个测试的基础上找到对模拟行为的粒度控制,而不是尝试实现支持每种用例的模拟(例如,控制模拟行为的某些特殊参数)。

让我们使用此新模拟程序实施一些测试:

// getStatus.spec.js

jest.mock('./requestBuilder');

const requestBuilder = require('./requestBuilder');
const getStatus = require('./getStatus');

describe('get status', () => {

    // Set up a mock builder before each test is run
    let builder;
    beforeEach(() => {
        builder = {
            addParam: jest.fn(),
            build: jest.fn()
        };
        requestBuilder.mockReturnValue(builder);
    });

    // every code path for get status calls request builder with a hard coded URL,
    // lets create an assertion for this method call that runs after each test execution.
    afterEach(() => {
        expect(requestBuilder).toHaveBeenCalledWith('http://fake.com/status');
    });

    it('when request builder creation throws error', () => {
        // Override the mocking behavior to throw an error
        requestBuilder.mockImplementation(() => {
            throw new Error('create error')
        });
        expect(getStatus()).toEqual({status: 'unknown'});
        expect(builder.build).not.toHaveBeenCalled();
    });

    it('when build throws an error', () => {
        // Set the mocking behavior to throw an error
        builder.build.mockImplementation(() => {
            throw new Error('build error')
        });
        expect(getStatus()).toEqual({status: 'unknown'});
        expect(builder.build).toHaveBeenCalled();
    });

    it('when request builder returns success', () => {
        // Set the mocking behavior to return ajaxSuccess value
        builder.build.mockReturnValue({ajaxSuccess: true});
        expect(getStatus()).toEqual({status: 'success'});
        expect(builder.build).toHaveBeenCalled();
    });

    it('when request builder returns failure', () => {
        // Set the mocking behavior to return ajaxSuccess value
        builder.build.mockReturnValue({ajaxSuccess: false});
        expect(getStatus()).toEqual({status: 'failure'});
        expect(builder.build).toHaveBeenCalled();
    });
});