Muliple patch in Python unitest not working - python

My test case looks like this. Following is the code:
#patch('something.mysqlclient')
#patch('something.esclient')
def testcase1(mysql,esclient):
esclient.return_value = 1
mysql.return_value = 3
assert something.modeul1.esclient == 1
assert something.modeul1.mysql == 3

Decorator works from bottom to top.
#patch('something.mysqlclient')
#patch('something.esclient')
def testcase1(esclient, mysql):
pass

Related

Pytest mocking: pass kwargs through side_effect function

I want to test a file called ninja.py wrote in Python3.6.
# File ninja.py
def what_to_do_result(result):
# Send a mail, write something in a file, play a song or whatever
def my_function(a, b):
# Step 1
result = a + b
# Step 2
if result == 3:
what_to_do_result(result)
elif result == 5:
what_to_do_result(result + 1)
else:
return True
I have started writing a test file called test_ninjapy and wrote some unittest. I do use Pytest.
import pytest
class MyTestException(Exception):
pass
def run_side_effect(*args, **kwargs):
raise MyTestException(kwargs["result"])
#pytest.fixture(name="resource")
def setup_fixture():
# Some code here
class TestNinja:
#staticmethod
def setup_method():
# Function called before each test
#staticmethod
def teardown_method():
# Function called after each test
#staticmethod
def test_my_function(mocker, resource):
# How to do this ???
mocker.patch("ninja.what_to_do_result", return_value=None, side_effect=run_side_effect)
# Then the test
assert 1 == 1 # -> This works
with pytest.raises(MyTestException):
ninja_function(a=1, b=2)
assert ninja_function(a=5, b=10)
The point is that I want to mock the function ninja.what_to_do_result and apply a side effect (= run a function).
I want the side effect to use the parameter (kwargs) or the function what_to_do_result.
But I don't know how to do this.
For example:
Because there are multiple possibilities (in the step 2, the call of what_to_do_result could be with 3 & 5, which are linked with 2 differents use cases I wxant to test.
Can you help me?
I did not found the related section in the documentation below.
Link to the documentation: https://github.com/pytest-dev/pytest-mock

unittest - How to test internal parameter in a function?

I'm having some issue while creating unittest for internal parameter.
My structure is:
[1] my_animal.py contains Myclass and method: do_bite()
my_animal.py
class Myclass():
def do_bite(self):
return 1
[2] my_module.py contains jobMain("") which is using the method from my_animal.py
my_module.py
import sys
from someclass import Myclass
def jobMain(directoryPath):
flag = -1
result = Myclass()
if result.do_bite() is None:
flag = 0
if result.do_bite() is 1:
flag = 1
if result.do_bite() is 2:
flag = 2
[3] my_test.py contains the unittest to test jobMain in my_module.py
my_test.py
# Mock Myclass.dobite to None
#pytest.fixture
def mock_dobite0():
with mock.patch('my_module.Myclass') as mocked_animal:
mocked_animal.return_value.do_bite.return_value = None
yield
# Mock Myclass.dobite to 1
#pytest.fixture
def mock_dobite1():
with mock.patch('my_module.Myclass') as mocked_animal:
mocked_animal.return_value.do_bite.return_value = 1
yield
# Mock Myclass.dobite to 2
#pytest.fixture
def mock_dobite2():
with mock.patch('my_module.Myclass') as mocked_animal:
mocked_animal.return_value.do_bite.return_value = 2
yield
# My unittest to test dobite() method
def test_dobite0(mock_Myclass, mock_dobite0):
jobMain("")
def test_dobite1(mock_Myclass, mock_dobite1):
jobMain("")
def test_dobite2(mock_Myclass, mock_dobite2):
jobMain("")
My question is: How to test 'flag' parameter inside JobMain?
'flag' para must be assigned the correct value.( eg: dobite = 1 => flag = 1)
The variable para only exists in the scope of jobMain. If you want to use the variable outside jobMain the most common ways are
1) return the value
This is quite obvious. Since jobMain is a function, it returns a value. Without an explicit return statement you return None. You could just
def jobmain(pth):
# do stuff and assign flag
return flag
# and inside tests
assert jobmain("") == 1
2) Use a class instead
If you want the jobMain to remember some state, then it is common practice to use objects. Then flag would be attribute of the object and could be accessed from outside, after you call any method (function) of JobMain. For example
class JobMain:
def __init__(self):
self.flag = -1
def run(self, pth):
result = Myclass()
if result.do_bite() is None:
self.flag = 0
if result.do_bite() is 1:
self.flag = 1
if result.do_bite() is 2:
self.flag = 2
# and inside test
job = JobMain()
job.run()
assert job.flag == 1
Note
I just copy-pasted your code for setting the flag. Note that you call do_bite() many times, if the resulting value is None or 1. Also, when testing against a number, one should use == instead of is.
How to test 'flag' parameter inside JobMain?
You don't. It's an internal variable. Testing it would be glass-box testing; the test will break if the implementation changes.
Instead, test the effect of flag. This is black-box testing. Only the interface is tested. If the implementation changes the test still works allowing the code to be aggressively refactored.
Note: If you don't hard code result = Myclass() you don't need to mock. Pass it in as an argument with the default being Myclass().
def jobMain(directoryPath, result=Myclass()):
Then you don't need to patch Myclass(). Instead, pass in a mock object.
# I don't know unittest.mock very well, but something like this.
mock = Mock(Myclass)
mock.do_bite.return_value = 2
jobMain('', result=mock)
This also makes the code more flexible outside of testing.

Skip specified Python unit-test from command line

I have bunch of unit-tests in my unit-test file. However, one of the tests I would like to skip only when running the unit-tests from command line. I know how to always skip it (#unittest.skip), but I want to somehow skip it only when running the unit-test file from command line. Is this possible?
Something like this:
test_all_my_tests.py -exclude test_number_five()
Thanks
Great question.
One idea could be command with arguments and in the arguments specify which tests to skip.
Then in your script you would parse the passed arguments and call your tests accordingly.
Your input would look like:
test_all_my_tests.py -exclude 5
and in the python script it would check for a "-exclude" argument and take the following argument as well.
Good luck!
You can have a look at #unittest.skipIf() or even implement your own skip-decorator:
Example
Here is a working example, where I implemented a custom decorator
def skipIfOverCounter(obj):
This decorator is attached to all tests like this:
#skipIfOverCounter
def test_upper(self):
The decorator increments a count and compares it to the console argument.
Output
Implemented 3 unit tests:
test_upper()
test_isupper()
test_split()
The I called python .\unittests.py 0
Skipped test 0
Ran 'test_isupper'
Ran 'test_split'
With param = 1: python .\unittests.py 1
Skipped test 1
Ran 'test_split'
Ran 'test_upper'
Skip the last test: python .\unittests.py 2
Skipped test 2
Ran 'test_isupper'
Ran 'test_upper'
Full working sample
import sys
import unittest
SKIP_INDEX = 0
COUNTER = 0
if len(sys.argv) > 1:
SKIP_INDEX = int(sys.argv.pop())
def skipIfOverCounter(obj):
global COUNTER
global SKIP_INDEX
if SKIP_INDEX == COUNTER:
print(f"Skipped test {COUNTER}")
COUNTER = COUNTER + 1
return unittest.skip("Skipped test")
COUNTER = COUNTER + 1
return obj
class TestStringMethods(unittest.TestCase):
#skipIfOverCounter
def test_upper(self):
print("Ran 'test_upper'")
self.assertEqual('foo'.upper(), 'FOO')
#skipIfOverCounter
def test_isupper(self):
print("Ran 'test_isupper'")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
#skipIfOverCounter
def test_split(self):
print("Ran 'test_split'")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
You could even extend this by adapting the decorator to only execute the first two tests or something like this

Python and pytest testing

I have to do some testing using pytest, but I have no idea where to start.
Here is piece of a code which i would like to test:
def print_url_and_id():
for item in movie_link[:100]:
print item.contents[1], "The ID of this movie is:", '"' + item.contents[1]['href'][7:16] + '"'
Could anyone tell me how it suppose to look like?
You can do something like this:
import pytest
def parametrized():
expected_results = ["movie_link_01", "movie_link_02"]
movie_link = ["movie_link_01", "movie_link_02", "movie_link_03"]
# you can define your new_movie_link list like this as you have done, but instead of
# printing it, add it to a this new_movie_link list
return [(item_1, item_2) for item_1, item_2 in zip(movie_link[:2], expected_results)]
#pytest.mark.parametrize("movie_link, expected", parametrized())
def test_parametrizer(movie_link, expected):
assert movie_link == expected

Patching a function using Mock

I have a test suite (using nose, not unittest), and I want to patch a function to return a specific sequence of values for every test in the test class. My first attempt, using a simplified example, was:
#patch('time.clock', MagicMock(side_effects=[1, 2]))
class Tests:
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2
However, the MagicMock instance is only created once, so the second test fails when the side effects run out. I can patch each test method separately, but I don't really want to duplicate the patch decorator over all of them (there are a lot more tests than in this example!) The other way I could do it is to create the patch in the setup code like this:
class Tests:
def setup(self):
self.old_clock = time.clock
time.clock = MagicMock(side_effects=[1, 2])
def teardown(self):
time.clock = self.old_clock
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2
But saving and restoring the original function definition seems like something that Mock should be able to do automatically. Is there another method of doing this that I'm missing? Or is my last example the best way of doing this?
a = (x for x in [1,2])
x = lambda : next(a)
x()
Out: 1
x()
Out: 2
Put your answers into a's list.
Change X for your desired name.
You should just apply the patch to every test, instead of applying it to the class:
class Tests:
#patch('time.clock', MagicMock(side_effects=[1, 2]))
def test_1(self):
assert time.clock() == 1
assert time.clock() == 2
#patch('time.clock', MagicMock(side_effects=[1, 2]))
def test_2(self):
assert time.clock() == 1
assert time.clock() == 2

Categories