unittest, running test from other file - python

I can't seem to get the Test1.test_something() in test2 to work.. not sure if it's because they are both inheriting from the same base?
Helper.py:
class baseTest(unittest.TestCase):
def setUp(self, param="Something"):
print param
pass
Test1.py
from Helper import baseTest
class test1(baseTest):
def setUp(self):
super(test1, self).setUp('foo')
def test_something(self):
assert 1 == 1, "One does not equal one."
Test2.py
from Helper import baseTest
import Test1
class test2(baseTest):
def setUp(self):
super(test2, self).setUp('bar')
def test_something(self):
Test1.test_somehing()
Now, I had this working previously, when I had the setUp for test1 and test2 within their classes, but once I had them both inherit from baseTest, I started getting a unbound method <method> must be called with Test instance as first argument (got nothing instead). Any suggestions?

The problem is that Test1.test_something() is an instance method, not a class method. So you can't just call it like that (besides, even if it is class method, it should have been Test1.test1.test_something).
One way to do it (without messing around with the unittest.TestCase mechanism):
Test2.py
import Test1
class test2(Test1.test1):
# whatever else
And you're done, test2 inherits Test1.test1.test_something() automatically. If you need your test2's test_something to do extra stuff, just do super(test2, self).test_something() within your overridden definition of test_something in test2 class.

Move the tests that are shared by both Test1 and Test2 classes into BaseTest:
test.py:
import unittest
import sys
class BaseTest(unittest.TestCase):
def setUp(self, param="Something"):
print param
pass
def test_something(self):
assert 1 == 1, "One does not equal one."
class Test1(BaseTest):
def setUp(self):
super(Test1, self).setUp('foo')
test2.py:
import test
import unittest
import sys
class Test2(test.BaseTest):
def setUp(self):
super(Test2, self).setUp('bar')

Related

How to mock a function which gets executed during the import time?

Here the ABC() and obj.print_1() get called during the import time and it prints "making object" and "printed 1" respectively. How can we mock all the three functions, __init__(), print_1(), and print_2()?
xyz.py
from abc import ABC
obj = ABC()
obj.print_1()
def func():
return obj.print_2(2)
abc.py
class ABC():
def __init__(self):
print("making object")
def print_1(self):
print("printed 1")
return None
def print_2(self, val):
print("printed ", val)
return None
Indeed, as soon as you import xyz, it will import abc and create an instance then call a method on it.
Solution : import abc yourself BEFORE xyz EVER GETS IMPORTED, and mock the methods defined in the class. And because we can't import a method, patch.object is required.
Note : I added a self as parameter in your ABC.print_1 method, otherwise it would be incorrect. Otherwise make it #staticmethod
Here is the test file I used :
import unittest
import unittest.mock as mock
from so74709409_abc import ABC
# no import of `xyz` here !
class Tests(unittest.TestCase):
def test__xyz_obj_calls_print1(self):
# __init__ must return None
with mock.patch.object(ABC, "__init__", **{"return_value": None}) as mock_init, \
mock.patch.object(ABC, "print_1") as mock_print1, \
mock.patch.object(ABC, "print_2") as mock_print2:
from so74709409_xyz import func # import now !
func()
mock_init.assert_called_once()
mock_print1.assert_called_once_with()
mock_print2.assert_called_once_with(2)
if __name__ == "__main__":
unittest.main()
But this is not very robust, if the module was already imported (maybe indirectly) before the test run, the import inside the test won't have any effect, and so it will fail (mocks not getting called). It can be a pain in a real test suite (with many tests running in sequence) because the previous test will already have imported xyz.
That's why it's better to do these kind of things in a if __name__=="__main__", or in a function called deliberately.
(beware : I assume you choose abc as a dummy name, but it is actually a standard library module for Abstract Base Classes)

Python Fire module not showing COMMANDS in `-h`

I am using the python Fire module with an abstract parent class and a child class. Not all functions are abstract, some functions do not need to be replicated for each child:
parent class
from abc import ABC, abstractmethod
class Foo(ABC):
#abstractmethod
def __init__(self, val=None):
# some initialisations
#abstractmethod
def fun1(self, file=None):
# Some calls
def fun2(self):
# Non abastract func... Some calls
child class (test.py)
import fire
from foo import Foo
class Child(Foo)
def __init__(self, val=None):
super().__init__(val)
# some initialisations
def fun1(file='path/to/file')
# do some stuff
if __name__ == '__main__':
fire.Fire(Child)
when I run python CLI with python -m test --help I do not get any COMMANDS i.e. Fire is not recognising any functions to run. However it is recognising the parent global variables and init flags to set so why is this happening?
try passing it the instantiated object instead like they do here
fire.Fire(Child())

Mocking a method inside class in python test

I am new to Python and writing a unit test for the already existing code.
I have the following Python code structure:
root_project:
-- src
-- signUp
-- __init__.py
-- abc.py
-- xyz.py
abc.py contains the following code:
from . import xyz
class Abc:
def __init__(self):
pass
def start_process(self):
xyz.start_timer()
I want to mock xyz.start_timer() inside method start_process of class Abc so that start_timer() mock version can be used.
How can I achieve this?
You can simply patch the start_timer function using mock.patch().
abc.py
import xyz
class Abc:
def __init__(self):
pass
def start_process(self):
xyz.start_timer()
test_abc.py
from unittest import mock, TestCase
from abc import Abc
class Test_Abc(TestCase):
#mock.patch("abc.start_timer")
def test_start_process(self, mock_start_timer):
# your test code
Notice that I have patched abc.start_timer and not xyz.start_timer.
You just need to patchxyz.start_timer(), I just added return to start_process to show that the patching really does what it should:
import xyz
import unittest
from unittest import mock
class Abc:
def __init__(self):
pass
def start_process(self):
return xyz.start_timer()
class Test_Abc(unittest.TestCase):
#mock.patch('xyz.start_timer', return_value=True)
def test_start_process(self, start_process):
a = Abc()
self.assertTrue(a.start_process())
if __name__ == '__main__':
unittest.main()
Out:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

unittest mock how to mock a method being called

I want to test that method a calls method b. These methods are in separate files, and are not a part of class object.
# file_a.py
from file_b import b
def a():
b()
# file_b.py
def b():
test
import unittest
from unittest import mock
from file_a import a
class MyTestCase(unittest.TestCase):
#mock.patch('file_b.b')
def test_b_called(self, mock):
a()
mock.assert_called()
if __name__ == "__main__":
unittest.main()
This fails with AssertionError: Expected 'b' to have been called.
Is there a right way to do this?
When you import a function into the current namespace, like in your example, the function will need to be patched in that namespace. In your case, you need:
#mock.patch('file_a.b')
You would patch file_b.b if you had done the import and use like this:
import file_b
def a():
file_b.b()

Unable to run addfinalizer function within a fixture with scope as class

Here’s my test code:
import string
import pytest
import tempfile
import os
#pytest.fixture(scope='class')
def TempFile(request):
(tmp_cfg_fd, tmp_cfg_file_path) = tempfile.mkstemp()
os.close(tmp_cfg_fd)
def RemoveTempFile():
print("Removing %r" %(tmp_cfg_file_path))
os.remove(tmp_cfg_file_path)
request.addfinalizer(RemoveTempFile)
return tmp_cfg_file_path
#pytest.mark.usefixtures(TempFile)
class Test:
def test1(self):
print("I'm in test1")
def test2(self):
print("I'm in test2")
When I run py.test on it, I get this error:
test_4.py:17: in <module>
#pytest.mark.usefixtures(TempFile)
test_4.py:14: in TempFile
request.addfinalizer(RemoveTempFile)
E AttributeError: class Test has no attribute 'addfinalizer'
When the fixture has scope='class', then the Test class fails to run addfinalizer.
But if the fixture has scope='function', and I call the TempFile fixture individually in test1 and test2 functions, then addfinalizer runs properly.
How can I get addfinalizer to run with scope='class'?
The usefixtures mark takes an string, if you change the mark into:
#pytest.mark.usefixtures('TempFile')
it will work correctly.

Categories