I am using unittest module for writing tests.
I need to test initialization of the object inside a testcase using different inputs.
For this purpose I am importing the class inside setUp(). But when I try to use the class inside test_*() functions, I get this error - NameError: name 'Example' is not defined
Here is my code sample-
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
import Example
def test_sample_function(self):
e = Example(1,2)
I know that I can simply import the class at top of the script. But I do not want to do that. I need to import it only during setup of the testscript.
Looking for some help here.
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
import Example
self.Example = Example
def test_sample_function(self):
e = self.Example(1,2)
There's no reason to import the module in setUp. The module is still available globally in sys.modules, but you've only bound it to a local name that goes away after setUp returns. Just import it globally.
import unittest
import Example
class TestExample(unittest.TestCase):
def test_sample_function(self):
e = Example(1,2)
Related
I am trying to mock a function that should get called when calling a class method:
# SomeClass.py
from some_module import some_function
class SomeClass:
def some_method(self, *a, **kw):
...
some_function()
...
# tests.py
from mock import patch
from some_package.SomeClass import SomeClass
class TestSomeClass:
#patch('SomeClass.some_function') # <- error
def test__some_function__called(self, mocked_function):
...
SomeClass().some_method()
mocked_function.assert_called()
However, I keep getting an error saying that SomeClass does not have a method called some_function.
The issue is due to the fact that the module name and the class name are the same, i.e. SomeClass. This is causing patch some confusion.
The solution: a combination of importlib and overriding the imported modules function with Mock():
# tests.py
import importlib
from mock import Mock
from some_package.SomeClass import SomeClass
class TestSomeClass:
def test__some_function__called(self):
some_class_module = importlib('some_package.SomeClass') # this is the actual module
some_class_module.some_function = Mock()
...
SomeClass().some_method()
some_class_module.some_function.assert_called() # <- no more error - tests pass
This is how I solved this issue - if anyone has an alternative solution it would be great to hear it. Hope this helps anyone with a similar issue.
I want to make use of my tempfile module to write files in my test case.
But I am having trouble referencing it when usinng mock.patch
Supposed I have this code, notice the patch as it is referencing the self.test_dir
import unittest
from unittest.mock import patch
import tempfile
class TestSomething(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.TemporaryDirectory()
def tearDown(self):
# Close the file, the directory will be removed after the test
self.test_dir.cleanup()
#patch("sample_module.SampleClass.base_url", self.test_dir)
def test_override(self):
pass
Running this code will result to this error
NameError: name 'self' is not defined
As the test_dir is being initialized in the setup and tearDown method then how can I make use of this tempfile.TemporaryDirectory
Any thoughts?
Is it possible to mock a module in python using unittest.mock? I have a module named config, while running tests I want to mock it by another module test_config. how can I do that ? Thanks.
config.py:
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
test_config.py:
CONF_VAR1 = "test_VAR1"
CONF_VAR2 = "test_VAR2"
All other modules read config variables from the config module. While running tests I want them to read config variables from test_config module instead.
If you're always accessing the variables in config.py like this:
import config
...
config.VAR1
You can replace the config module imported by whatever module you're actually trying to test. So, if you're testing a module called foo, and it imports and uses config, you can say:
from mock import patch
import foo
import config_test
....
with patch('foo.config', new=config_test):
foo.whatever()
But this isn't actually replacing the module globally, it's only replacing it within the foo module's namespace. So you would need to patch it everywhere it's imported. It also wouldn't work if foo does this instead of import config:
from config import VAR1
You can also mess with sys.modules to do this:
import config_test
import sys
sys.modules["config"] = config_test
# import modules that uses "import config" here, and they'll actually get config_test
But generally it's not a good idea to mess with sys.modules, and I don't think this case is any different. I would favor all of the other suggestions made over it.
foo.py:
import config
VAR1 = config.CONF_VAR1
def bar():
return VAR1
test.py:
import unittest
import unittest.mock as mock
import test_config
class Test(unittest.TestCase):
def test_one(self):
with mock.patch.dict('sys.modules', config=test_config):
import foo
self.assertEqual(foo.bar(), 'test_VAR1')
As you can see, the patch works even for code executed during import foo.
If you want to mock an entire module just mock the import where the module is used.
myfile.py
import urllib
test_myfile.py
import mock
import unittest
class MyTest(unittest.TestCase):
#mock.patch('myfile.urllib')
def test_thing(self, urllib):
urllib.whatever.return_value = 4
Consider this following setup
configuration.py:
import os
class Config(object):
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
class TestConfig(object):
CONF_VAR1 = "test_VAR1"
CONF_VAR2 = "test_VAR2"
if os.getenv("TEST"):
config = TestConfig
else:
config = Config
now everywhere else in your code you can use:
from configuration import config
print config.CONF_VAR1, config.CONF_VAR2
And when you want to mock your coniguration file just set the environment variable "TEST".
Extra credit:
If you have lots of configuration variables that are shared between your testing and non-testing code, then you can derive TestConfig from Config and simply overwrite the variables that need changing:
class Config(object):
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
CONF_VAR3 = "VAR3"
class TestConfig(Config):
CONF_VAR2 = "test_VAR2"
# CONF_VAR1, CONF_VAR3 remain unchanged
If your application ("app.py" say) looks like
import config
print config.var1, config.var2
And gives the output:
$ python app.py
VAR1 VAR2
You can use mock.patch to patch the individual config variables:
from mock import patch
with patch('config.var1', 'test_VAR1'):
import app
This results in:
$ python mockimport.py
test_VAR1 VAR2
Though I'm not sure if this is possible at the module level.
I'm writing unit tests to validate my project functionalities. I need to replace some of the functions with mock function and I thought to use the Python mock library. The implementation I used doesn't seem to work properly though and I don't understand where I'm doing wrong. Here a simplified scenario:
root/connector.py
from ftp_utils.py import *
def main():
config = yaml.safe_load("vendor_sftp.yaml")
downloaded_files = []
downloaded_files = get_files(config)
for f in downloaded_files:
#do something
root/utils/ftp_utils.py
import os
import sys
import pysftp
def get_files(config):
sftp = pysftp.Connection(config['host'], username=config['username'])
sftp.chdir(config['remote_dir'])
down_files = sftp.listdir()
if down_files is not None:
for f in down_files:
sftp.get(f, os.path.join(config['local_dir'], f), preserve_mtime=True)
return down_files
root/tests/connector_tester.py
import unittest
import mock
import ftp_utils
import connector
def get_mock_files():
return ['digital_spend.csv', 'tv_spend.csv']
class ConnectorTester(unittest.TestCase)
#mock.patch('ftp_utils.get_files', side_effect=get_mock_files)
def test_main_process(self, get_mock_files_function):
# I want to use a mock version of the get_files function
connector.main()
When I debug my test I expect that the get_files function called inside the main of connector.py is the get_mock_files(), but instead is the ftp_utils.get_files(). What am I doing wrong here? What should I change in my code to properly call the get_mock_file() mock?
Thanks,
Alessio
I think there are several problems with your scenario:
connector.py cannot import from ftp_utils.py that way
nor can connector_tester.py
as a habit, it is better to have your testing files under the form test_xxx.py
to use unittest with patching, see this example
In general, try to provide working minimal examples so that it is easier for everyone to run your code.
I modified rather heavily your example to make it work, but basically, the problem is that you patch 'ftp_utils.get_files' while it is not the reference that is actually called inside connector.main() but probably rather 'connector.get_files'.
Here is the modified example's directory:
test_connector.py
ftp_utils.py
connector.py
test_connector.py:
import unittest
import sys
import mock
import connector
def get_mock_files(*args, **kwargs):
return ['digital_spend.csv', 'tv_spend.csv']
class ConnectorTester(unittest.TestCase):
def setUp(self):
self.patcher = mock.patch('connector.get_files', side_effect=get_mock_files)
self.patcher.start()
def test_main_process(self):
# I want to use a mock version of the get_files function
connector.main()
suite = unittest.TestLoader().loadTestsFromTestCase(ConnectorTester)
if __name__ == "__main__":
unittest.main()
NB: what is called when running connector.main() is 'connector.get_files'
connector.py:
from ftp_utils import *
def main():
config = None
downloaded_files = []
downloaded_files = get_files(config)
for f in downloaded_files:
print(f)
connector/ftp_utils.py unchanged.
My (simplified) project layout is as follows:
/__init__.py
/test.py
/lib/__init__.py
/lib/client.py
my test.py is simply:
import lib.client
A = client()
A.Test()
and my lib\client.py begins as follows:
import ui #(another class in the lib dir)
class client(object):
"""
(Blah)
"""
UI = None
def __init__():
UI = ui()
def Test():
print "Success"
When I attempt to run test.py, I can step into the code and see that the definitions in client are parsed, however, when I get to the line where I instantiate a client, I get the following exception:
NameError: name 'client' is not defined
if I change that line to be:
A = lib.client()
Then I get
'module' object is not callable
What am I missing?
the lib.client object you have after import lib.client is the module, not the class. To instantiate the class you need to call the class in the module object:
A = lib.client.client()
or, as #rantanplan said, import the class from the module
from lib.client import client
A = client()
I just understood that you do the imports the Java way.
In python when you do :
import lib.client
You don't make available all the definitions in that module. You just
made available the actual module - the client.py
So either you keep the import scheme as you have now and do
import lib.client
A = lib.client.client()
or
from lib.client import client
A = client()
Also I suggest you name your python classes with capitalized camelcase
i.e.
class Client(object):
As it is the python convention.