模拟在另一个函数中使用的函数

Posted

技术标签:

【中文标题】模拟在另一个函数中使用的函数【英文标题】:mock a function which is used in another function 【发布时间】:2018-01-21 15:09:41 【问题描述】:

我正在为我在 react redux 中的异步操作编写测试,为了解决我在此处简化代码的问题。这是我的动作函数:

export function updateUserAuthenticationStatus()
return function(dispatch)
   return axios.get(getLoginStatusUrl())
        .then(response => 
               const middlewares = [thunk];
               const mockStore = configureMockStore(middlewares);
               const store = mockStore();
    return store.dispatch(updateUserAuthenticationStatus()).then(()=>
       //expect(store.getActions()[0]).to.eql(expectedActions);
    );
            );
        ).catch(function(response)
    );
  

所以问题在于函数 getLoginStatusUrl() 会在 cookie 中进行几次检查并根据某些条件返回适当的 url。所以我想要模拟这个函数以返回例如 test.com 然后我可以按如下方式测试我的操作:

it("", () => 
        **here I want to mock getLoginStatusUrl() to return test.com**
    nock("test.com")
        .get("/")
        .reply(200,"test detail");

)

在这种情况下如何模拟 getLoginStatusUrl() 以返回 test.com?

【问题讨论】:

【参考方案1】:

用 sinon 试试这个。

import getLoginStatusUrl from './some/path.js'

let stub = sinon.stub(),
opts =  call: getLoginStatusUrl() ;

stub.withExactArgs().returns("somePredefinedReturnValue")

【讨论】:

谢谢,如果 getLoginStatusUrl 是私有函数,这行得通吗? 将函数导出为像export function getLoginStatusUrl() ...这样的ES模块,然后在这里导入。我假设你在你的行动中做同样的事情。 是的,但是为了编写代码的最佳实践,由于测试目的而导出函数是个好主意吗? 通常我们不会为了测试而改变代码。您是否在操作中调用本地函数?如果是这样,您可以将其导出为 ES 模块并将其导入您的测试文件。只需在函数定义的开头添加export。顺便说一句,如果函数是本地的,那么你甚至不能对其进行单元测试。【参考方案2】:

您不需要专门返回 test.com。使用诸如axios-mock-adapter 之类的库。我没有亲自使用它,但我使用 fetch-mock 来模拟 fetch api 请求,因此这个概念应该完全相同。

假设getLoginStatusUrl() 返回/loginStatus,(因为您还没有显示它返回的内容)。

例子:

var axios = require('axios');
var MockAdapter = require('axios-mock-adapter');

// This sets the mock adapter on the default instance
var mock = new MockAdapter(axios);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet('/loginStatus').reply(200, 
  loginSuccess: true
);

axios.get('/loginStatus')
  .then(function(response) 
    console.log(response.data);
  );

示例代码未经测试,但希望您能理解。只需阅读库 README.md。

在您想要存根/模拟在这样的 axios 请求中未使用的私有导入的场景中,如果您使用诸如导入之类的 es6 语法,则可以使用 rewire 或 babel-plugin-rewire。

@HamedMinaee 如果你根本不知道路径,你可以做一些类似onGet('/') 的事情,它都在 README.md 中。在测试之后,我想他们是一种重置它的方法,这样并不是所有使用 axios 的测试都会受到它的影响。

afterEach(() => 
    // reset the axios mock here so that '/' doesn't affect all requests or something.
);

【讨论】:

非常感谢您的回答,我将开始调查并让您知道结果。只是一个问题:我有一个函数 getLoginStatusUrl 用于获取 url,我们根本不知道路径,但在模拟函数中,我们有 onGet('/loginStatus') 我们定义了路径 '/loginStatus' 它是如何解决的这个问题? 非常感谢我正在努力,让您知道结果 当我检查自述文件时:如果你根本不知道路径,你可以做类似 onGet('/') 我找不到任何东西。我错过了什么吗? @HamedMinaee 或者不指定路径,例如onGet()。这是自述文件中的内容

以上是关于模拟在另一个函数中使用的函数的主要内容,如果未能解决你的问题,请参考以下文章

Python如何在另一个函数中模拟一个函数

Python模拟补丁在另一个函数内的一个函数

使用 python 的模拟 patch.object 更改在另一个方法中调用的方法的返回值

如何使用 sinon 使用 axios.post 模拟异步方法?

调用函数时模拟器抛出异常(android studio)

如何使用降雪导出预定义函数?