For how to exclude the if __name__ == '__main__'
you can write a coverage configuration file and add in the section report:
[report] exclude_lines = if __name__ == .__main__.:
For example, you could use imp.load_source()
like so:
import imp
runpy = imp.load_source('__main__', '/path/to/runpy.py')
I was working on a module that contained a dozen or so scripts all ending with this exact copypasta:
if __name__ == '__main__':
if '--help' in sys.argv or '-h' in sys.argv:
print(__doc__)
else:
sys.exit(main())
Not horrible, sure, but not testable either. My solution was to write a new function in one of my modules:
def run_script(name, doc, main):
""
"Act like a script if we were invoked like a script."
""
if name == '__main__':
if '--help' in sys.argv or '-h' in sys.argv:
sys.stdout.write(doc)
else:
sys.exit(main())
and then place this gem at the end of each script file:
run_script(__name__, __doc__, main)
Python 3 solution:
import os
from importlib.machinery
import SourceFileLoader
from importlib.util
import spec_from_loader, module_from_spec
from importlib
import reload
from unittest
import TestCase
from unittest.mock
import MagicMock, patch
class TestIfNameEqMain(TestCase):
def test_name_eq_main(self):
loader = SourceFileLoader('__main__',
os.path.join(os.path.dirname(os.path.dirname(__file__)),
'__main__.py'))
with self.assertRaises(SystemExit) as e:
loader.exec_module(module_from_spec(spec_from_loader(loader.name, loader)))
Using the alternative solution of defining your own little function:
# module.py
def main():
if __name__ == '__main__':
return 'sweet'
return 'child of mine'
You can test with:
# Override the `__name__` value in your module to '__main__' with patch('module_name.__name__', '__main__'): import module_name self.assertEqual(module_name.main(), 'sweet') with patch('module_name.__name__', 'anything else'): reload(module_name) del module_name import module_name self.assertEqual(module_name.main(), 'child of mine')
- I wrapped
if __name__ == "__main__":
in a function to make it easily testable, and then called that function to retain logic:
# myapp.module.py
def main():
pass
def init():
if __name__ == "__main__":
main()
init()
- I mocked the
__name__
usingunittest.mock
to get at the lines in question:
from unittest.mock
import patch, MagicMock
from myapp
import module
def test_name_equals_main():
# Arrange
with patch.object(module, "main", MagicMock()) as mock_main:
with patch.object(module, "__name__", "__main__"):
# Act
module.init()
# Assert
mock_main.assert_called_once()
If you are sending arguments into the mocked function, like so,
if __name__ == "__main__":
main(main_args)
If desired, you can also add a return_value
to the MagicMock()
like so:
with patch.object(module, "main", MagicMock(return_value = 'foo')) as mock_main:
I found this solution helpful. Works well if you use a function to keep all your script code. The code will be handled as one code line. It doesn't matter if the entire line was executed for coverage counter (though this is not what you would actually actually expect by 100% coverage) The trick is also accepted pylint. ;-)
if __name__ == '__main__': \
main()
It is recommended that you use TestCase implementations to group tests together according to the features they test. unittest provides a mechanism for this: the test suite, represented by unittest’s TestSuite class. In most cases, calling unittest.main() will do the right thing and collect all the module’s test cases for you and execute them.,In some cases, the existing tests may have been written using the doctest module. If so, doctest provides a DocTestSuite class that can automatically build unittest.TestSuite instances from the existing doctest-based tests.,This class represents an aggregation of individual test cases and test suites. The class presents the interface needed by the test runner to allow it to be run as any other test case. Running a TestSuite instance is the same as iterating over the suite, running each test individually.,A testcase is created by subclassing unittest.TestCase. The three individual tests are defined with methods whose names start with the letters test. This naming convention informs the test runner about which methods represent tests.
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
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()
... -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 3 tests in 0.000 s OK
test_isupper(__main__.TestStringMethods)...ok test_split(__main__.TestStringMethods)...ok test_upper(__main__.TestStringMethods)...ok -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 3 tests in 0.001 s OK
python - m unittest test_module1 test_module2 python - m unittest test_module.TestClass python - m unittest test_module.TestClass.test_method
python - m unittest tests / test_something.py
python - m unittest - v test_module
Since I have convinced you to use the unit testing with your python source codes, I will illustrate the process in detail. There are various test-runners in python like unittest, nose/nose2, pytest, etc. We will use unittest to test our python source code. The unittest is an inbuilt module and using it is as easy as:-,You can run it from the terminal using the code:- python -m unittest test_calculator.py,I will wrap up this tutorial with a hope that you will be comfortable in unit testing your python source code.,Why to unit test your python source code?
Since I have convinced you to use the unit testing with your python source codes, I will illustrate the process in detail. There are various test-runners in python like unittest, nose/nose2, pytest, etc. We will use unittest to test our python source code. The unittest is an inbuilt module and using it is as easy as:-
import unittest
Let us assume, we have the following python code:-
# calculator.py
def add(x, y):
""
"Simple addition function"
""
return x + y
def subtract(x, y):
""
"Simple subtraction function"
""
return x - y
def multiply(x, y):
"Simple multiplication function"
return x * y
def divide(x, y):
"Simple division function"
if y == 0:
raise ValueError("Can not divide a number by 0.")
return x / y
We will create a new file for the test cases of the code. The general convention is to use either test_filename.py or filename_test.py. We will use test_filename.py. We will keep both the files in the same directory to make the imports and usage relatively easier.
#test_calculator.py
import unittest
import calculator
class TestCalculator(unittest.TestCase):
def test_add(self):
self.assertEqual(calculator.add(1, 5), 6)
- You can run it from the terminal using the code:-
python -m unittest test_calculator.py
- You can also run it from the terminal using the code:-
python -m unittest
This will automatically detect all the unit tests and run them. The downside of it is that if you have multiple files and tests, it will run all of them. - The last and my favorite method is to use the dunders method:
if __name__ == '__main__':
unittest.main()
Then you can run the test using the code:-python test_calculator.py
The advantage of using this method is that you can run the test from the text-editor as well.
Running the above test will give us the following output:-
. -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 1 test in 0.000 s OK
A method by which individual units of source code. Wikipedia says In computer programming, unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine if they are fit for use.,If possible everything in our codebase, each and every function. But it depends as a choice of the developers. You can skip it if it is not practical to write a robust test. As Nick Coghlan said in a guest session – … with a solid test suite, you can make big changes, confident that the externally visible behavior will remain the same,We are importing unittest module first and then the required functions which we want to test.,Simple testing in Python What we should test ? Unit testing unittest module Factorial code Which function to test ? Our first test case Description Different assert statements Testing exceptions mounttab.py After refactoring Test coverage Coverage Example
import sys def fact(n): "" " Factorial function : arg n: Number: returns: factorial of n "" " if n == 0: return 1 return n * fact(n - 1) def div(n): "" " Just divide "" " res = 10 / n return res def main(n): res = fact(n) print(res) if __name__ == '__main__': if len(sys.argv) > 1: main(int(sys.argv[1]))
$ python factorial.py 5
import unittest from factorial import fact class TestFactorial(unittest.TestCase): "" " Our basic test class "" " def test_fact(self): "" " The actual test. Any method which starts with `` test_`` will considered as a test case. "" " res = fact(5) self.assertEqual(res, 120) if __name__ == '__main__': unittest.main()
$ python factorial_test.py . -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 1 test in 0.000 s OK
self.assertRaises(ZeroDivisionError, div, 0)
import unittest from factorial import fact, div class TestFactorial(unittest.TestCase): "" " Our basic test class "" " def test_fact(self): "" " The actual test. Any method which starts with `` test_`` will considered as a test case. "" " res = fact(5) self.assertEqual(res, 120) def test_error(self): "" " To test exception raise due to run time error "" " self.assertRaises(ZeroDivisionError, div, 0) if __name__ == '__main__': unittest.main()
Posted on Mar 30, 2020 , Joined Mar 28, 2019
print("I am module.py")
def func1():
return "The first function was called"
if __name__ == "__main__":
print(func1())
# When this module(or script) is run this would be the output
I am module.py
The first
function was called
import module print("I would be printed after 'I am module.py'") # When this script is run, this would be the output I am module.py I would be printed after 'I am module.py' # Note, func1 wasn 't called