How to Mock an Import

How to mock an import

You can assign to sys.modules['B'] before importing A to get what you want:

test.py:

import sys
sys.modules['B'] = __import__('mock_B')
import A

print(A.B.__name__)

A.py:

import B

Note B.py does not exist, but when running test.py no error is returned and print(A.B.__name__) prints mock_B. You still have to create a mock_B.py where you mock B's actual functions/variables/etc. Or you can just assign a Mock() directly:

test.py:

import sys
sys.modules['B'] = Mock()
import A

How to jest.mock an ES6 module import?

Have you try to mock like this

jest.mock('@mine/my-lovely-libary', () => ({
doSomething: () => doSomethingMock,
}));

here doSomething is a method from your npm library

doSomethingMock can be jest.fn() or something like this const doSomethingMock = 'mockTestValue'

How to mock the import of a module in python?

Since your function search_for_data is using the name config imported in func's global namespace, you need to override that instead of the overriding folder.some_config_module.

@patch('folder.func.config')

An import like import folder.some_config_module as config is equivalent to doing:

import folder.some_config_module
config = folder.some_config_module
del folder.some_config_module

Hence it adds the variable config to that module(func.py)'s namespace and that's what then search_for_data is using. From search_for_data's perspective, it doesn't matter if config is a name that refers to a module or it refers to something else, it just knows that it needs to load that name from the global namespace(in this case it's the module func.py)


At runtime search_for_data will look for config in its global namespace(search_for_data.__globals__), mock patches this globals dictionary and replaces the name config in this dictionary temporarily with the mock object and during teardown it restores it back.

import os.path as path
from unittest.mock import patch

def func():
print(path)

print(f"Before patch: {func.__globals__['path']}")
with patch("__main__.path"):
print(f"During patch: {func.__globals__['path']}")
func()

print(f"After patch: {func.__globals__['path']}")

Outputs:

Before patch: <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>
During patch: <MagicMock name='path' id='140233829017776'>
<MagicMock name='path' id='140233829017776'>
After patch: <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>

Spying On/Mocking Import of an Import

Late to the party but just in case anyone else is facing the same issue.

I solved it by importing the module dependency in the test file and mocking the whole module first, then just the methods I needed.

import { client } from 'client';

vi.mock('client', () => {
const client = vi.fn();
client.get = vi.fn();

return { client }
});

Then in those tests calling client.get() behind the scenes as a dependency, just add

  client.get.mockResolvedValue({fakeResponse: []});

and the mocked function will be called instead of the real implementation.

If you are using a default export, look at the vitest docs since you need to provide a default key.

If mocking a module with a default export, you'll need to provide a default key within the returned factory function object. This is an ES modules specific caveat, therefore jest documentation may differ as jest uses commonJS modules.

How can I mock an ES6 module import using Jest?

Fast forwarding to 2020, I found this blog post to be the solution: Jest mock default and named export

Using only ES6 module syntax:

// esModule.js
export default 'defaultExport';
export const namedExport = () => {};

// esModule.test.js
jest.mock('./esModule', () => ({
__esModule: true, // this property makes it work
default: 'mockedDefaultExport',
namedExport: jest.fn(),
}));

import defaultExport, { namedExport } from './esModule';
defaultExport; // 'mockedDefaultExport'
namedExport; // mock function

Also one thing you need to know (which took me a while to figure out) is that you can't call jest.mock() inside the test; you must call it at the top level of the module. However, you can call mockImplementation() inside individual tests if you want to set up different mocks for different tests.

How to mock an import in a different python source under test?

Here's sort of what I'm proposing with the sys.modules solution. You have options as far as if you want to do that mock globally, in each test case:

'''bad_module.py'''
raise RuntimeError("don't import me")

'''my_module.py'''
from bad_module import somestuff

def my_func():
pass

'''test_my_module.py'''
import sys
import unittest

from unittest import mock

def test_stuff():
sys.modules['bad_module'] = mock.Mock()
from my_module import my_func
my_func()

If I don't mock I get this:

...
File "/home/wholevinski/so_test/mock_import/test_my_module.py", line 2, in <module>
from my_module import my_func
File "/home/wholevinski/so_test/mock_import/my_module.py", line 1, in <module>
from bad_module import somestuff
File "/home/wholevinski/so_test/mock_import/bad_module.py", line 1, in <module>
raise RuntimeError("don't import me")
RuntimeError: don't import me

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

With the mock I get this:

(p36) [localhost mock_import]$ nosetests test_my_module.py 
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

How to mock an imported array and test the using Function

You are testing the check function, you should NOT stub it. Like your said, you should mock the myarray in test cases. You could mutate the value of myarray before require/import the checkFunction.js module. Make sure to clear the module cache before running each test case, so that subsequent imports of the constants module will give you a fresh myarray, not the mutated one.

E.g.

constants.js:

export const myarray = ['apples', 'oranges', 'pears'];

checkFunction.js:

import { myarray } from './constants';

export function check(value) {
console.log('myarray: ', myarray);
return myarray.includes(value);
}

checkFunction.test.js:

import { expect } from 'chai';

describe('72411318', () => {
beforeEach(() => {
delete require.cache[require.resolve('./checkFunction')];
delete require.cache[require.resolve('./constants')];
});
it('should pass', () => {
const { myarray } = require('./constants');
myarray.splice(0, myarray.length);
myarray.push('beef', 'lobster');
const { check } = require('./checkFunction');
expect(check('apples')).to.be.false;
});

it('should pass 2', () => {
const { check } = require('./checkFunction');
expect(check('apples')).to.be.true;
});
});

Test result:

  72411318
myarray: [ 'beef', 'lobster' ]
✓ should pass (194ms)
myarray: [ 'apples', 'oranges', 'pears' ]
✓ should pass 2

2 passing (204ms)


Related Topics



Leave a reply



Submit