Right way to write Unit-Tests in module? - python

I want to write tests for my main file,calc.py, with unittest in module file, MyTests.py.
Here is my main python file, calc.py:
import myTests
def first(x):
return x**2
def second(x):
return x**3
def main():
one = first(5)
two = second(5)
if __name__ == "__main__":
main()
try:
myTests.unittest.main()
except SystemExit:
pass
And here is my MyTests.py file:
import unittest
import calc
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.testInput = 10
def test_first(self):
output = calc.first(self.testInput)
correct = 100
assert(output == correct)
def test_second(self):
output = calc.second(self.testInput)
correct = 1000
assert(output == correct)
When i run my calc.py, i get the following output:
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Why does unittest prints me that "Ran 0 test"?
And what is the right way to write unittest in module?

unittests.main() looks for TestCase instances in the current module. Your module has no such testcases; it only has a myTests global.
Best practice is to run the tests themselves. Add the __main__ section there to the myTests.py file:
import unittest
import calc
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.testInput = 10
def test_first(self):
output = calc.first(self.testInput)
correct = 100
assert(output == correct)
def test_second(self):
output = calc.second(self.testInput)
correct = 1000
assert(output == correct)
if __name__ == '__main__':
unittest.main()
and run python myTests.py instead.
Alternatively, pass in the imported myTests module into unittest.main(). You may want to move the import myTests line down into __main__, because you have a circular import too. That is fine in your case, myTests doesn't use any globals from calc outside of the test cases, but it is better to be explicit about this.
if __name__ == "__main__":
main()
try:
import myTests
myTests.unittest.main(myTests)
except SystemExit:
pass

Related

patching a function if that function is imported using the from statement

I have a case similar to the following code where I am trying to patch a fucntion that is imported using the from statement:
from module1 import function1
def function2():
function1_result = function1()
return 2*function1_result
and then the testing code is:
from unittest import patch
def test_function2():
func1_value = 5
with patch("module1.function1", return_value=func1_value) as patched_func1:
function2_value = function2()
assert function2_value==2*func1_value
However the code runs but it doesn't use the patched function 1 and actually calls the function. However, if I change the import statement to just import module1 then the test runs fine.
See Where to patch doc, the examples in the documentation are very clear.
module1.py:
def function1():
return 1
module2.py:
from module1 import function1
def function2():
function1_result = function1()
return 2*function1_result
test_module2.py:
from unittest import TestCase
from unittest.mock import patch
import unittest
from module2 import function2
class TestModule2(TestCase):
def test_function2(self):
func1_value = 5
with patch("module2.function1", return_value=func1_value) as patched_func1:
function2_value = function2()
assert function2_value == 2*func1_value
if __name__ == '__main__':
unittest.main()
Test result:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Python - unittest, mock, patch, input

so i've got a problem with my code.
File 1:
class Abc(object):
...
def function1(self):
#do something
def function2(self):
x = input()
return x+1
and now i'm trying to test function 2 so i wrote a test for it and i don't know what i am doing wrong:
from unittest.mock import patch
import unittest
from file1 import *
class TestBackend(unittest.TestCase):
def test_mode_first(self):
self.assertEqual(Abc().funcion1(), 30)
#patch('funcion2.input', create=True)
def test_mode_second(self, mocked_input):
mocked_input.side_effect = ["QWE"]
result = Abc().funcion2()
self.assertEqual(result, 10)
if __name__ == '__main__':
unittest.main()
i get ModuleNotFoundError: No module named 'function2'
so what i am doing wrong in here?
thanks for your help :)
You get ModuleNotFoundError because funcion2 is not a module. patch doc is clear about this:
target should be a string in the form 'package.module.ClassName'. The
target is imported and the specified object replaced with the new
object, so the target must be importable from the environment you are
calling patch() from. The target is imported when the decorated
function is executed, not at decoration time.
This works for me when executed with python3 -m unittest discover from the directory the files are in.
BTW you have a couple of typos in your example, e.g. Abc().funcion2(), note the missing t in funcion2.
Also, try not to use from … import *: https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html#using-wildcard-imports-from-import
# file1.py
class Abc(object):
def function1(self):
return 30
def function2(self):
x = input()
return x + "1"
# test_file1.py
import unittest
from unittest.mock import patch
from file1 import Abc
class TestBackend(unittest.TestCase):
def test_mode_first(self):
self.assertEqual(Abc().function1(), 30)
#patch('builtins.input')
def test_mode_second(self, mocked_input):
mocked_input.return_value = "QWE"
result = Abc().function2()
self.assertEqual(result, "QWE1")

Python Define Unit Test Classes Together with Code

I am rapid prototyping so for now I would like to write unit tests together with the code I am testing - rather than putting the tests in a separate file. However, I would only like to build the test an invoke them if we run the code in the containing file as main. As follows:
class MyClass:
def __init(self)__:
# do init stuff here
def myclassFunction():
# do something
if __name__ == '__main__':
import unittest
class TestMyClass(unittest.TestCase):
def test_one(self):
# test myclassFunction()
suite = unittest.TestLoader().loadTestsFromTestCase(TestMyClass)
unittest.TextTestRunner(verbosity=2).run(suite)
This of course doesn't run as unittest is unable to find or make use of the test class, TestMyClass. Is there a way to get this arrangement to work or do I have to pull everything out of the if __name__ == '__main__' scope except the invocation to unittest?
Thanks!
If you move your TestMyClass above of if __name__ == '__main__'
you will get exactly what you want:
Tests will run only when file executed as main
Something like this
import unittest
class MyClass:
def __init(self)__:
# do init stuff here
def myclassFunction():
# do something
class TestMyClass(unittest.TestCase):
def test_one(self):
if __name__ == '__main__':
unittest.main()

Mocking __main__

I would like to ensure with tests that:
- the application cannot be imported
- the application can be started as a real application (i.e: python src.py)
I'm interested about that, why the following is not working:
src.py
class A:
def x(self):
print('this is x')
if __name__ == '__main__':
A().x()
test.py (snippet)
class Test(unittest.TestCase):
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
mock_x.assert_any_call()
This test fails... why?
Because the name of the module when imported is src, not __main__.
The easiest solution would be to move that code into a function:
def main():
A().x()
if __name__ == '__main__':
main()
and in your test, you would invoke src.main()
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
src.main()
mock_x.assert_any_call()
To test that a module is not importable you do not need to use mocks.
See assertRaises.
Just check if an error is thrown on import od module.
with self.assertRaises(...):
...

Simple Python Unit Testing With Test Cases In Multiple Folders

I am new to unit testing using python and am designing a simple unit test setup. This is what I have made:
/python_test
__init__.py
unittest_main.py
test_abc/
__init__.py
test_abc.py
test_pqr/
__init__.py
test_pqr.py
All the __init__.py files are empty and the other files have some basic content:
unittest_main.py
import os
import sys
import glob
import inspect
import unittest
from sets import Set
if len(sys.argv) > 1:
testCases = glob.glob('test_*')
testTargets = Set([])
for testTarget in sys.argv:
if testTarget == "test_all":
testTargets = testCases
break
else:
for testCase in testCases:
if testCase == testTarget:
testTargets.add(testCase)
break
if len(testTargets) > 0:
print testTargets
suiteList = []
for testTarget in testTargets:
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],testTarget)))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
suiteList.append(unittest.defaultTestLoader.loadTestsFromModule("python_test"+"."+testTarget+"."+testTarget))
mainSuite = unittest.TestSuite(suiteList)
unittest.TextTestRunner(verbosity=1).run(mainSuite)
else:
"No Proper Test Targets Specified"
else:
print "No Test Targets Specified"
test_abc.py
import unittest
class test_abc(unittest.TestCase):
def setUp(self):
print "Setup Complete"
def tearDown(self):
print "Tear Down Complete"
def test_abc_main(self):
self.assertEqual(1, 2, "test-abc Failure")
if __name__ == "__main__":
unittest.main()
test_pqr.py
import unittest
class test_pqr(unittest.TestCase):
def setUp(self):
print "Setup Complete"
def tearDown(self):
print "Tear Down Complete"
def test_abc_main(self):
self.assertEqual(1, 2, "test-pqr Failure")
if __name__ == "__main__":
unittest.main()
Question:
I am able to test the test cases separately but when I use the parent directly file to run all the tests, nothing happens?
$ ~/src/python_test$ python unittest_main.py test_all
['test_pqr', 'test_abc']
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
The installed Python Version is 2.7.3
Because you're passing module names to the loader, you want to use loadTestsFromName instead of loadTestsFromModule.

Categories

Resources