Hello! I’m attempting to follow some tutorials on unit testing with Python. One of them is a video tutorial Unit Tests in Python on the Socratica channel. Everyone in the comments seems to be making out just fine, and I’m following the instructor’s directions to the letter, yet I get a different result. It’s driving me mad lol.
In the video, the instructor creates two text files, one called circles.py
in which she defines a function circle_area(r)
, and another called test_circles.py
in which she writes some unit tests. In my attempt to follow along, I’ve ended up with two files structured like so:
/home/yo_scottie_oh/Projects/PythonTutorials/Socratica/Circles
├── circles.py
└── test_circles.py
circles.py
:
from math import pi
def circle_area(r):
return pi*(r**2)
# Test function
radii = [2, 0, -3, 2 + 5j, True, "radius"]
message = "Area of circles with r = {radius} is {area}."
for r in radii:
A = circle_area(r)
print(message.format(radius=r,area=A))
test_circles.py
:
import unittest
from circles import circle_area
from math import pi
class TestCircleArea(unittest.TestCase):
def test_area(self):
# Test areas when radius >=0
self.assertAlmostEqual(circle_area(1),pi)
self.assertAlmostEqual(circle_area(0),0)
self.assertAlmostEqual(circle_area(2.1),pi*2.1**2)
Where I’m getting tripped up is at 4:32 in the video, the instructor says to run the unit tests by opening a shell, going to the directory that contains both the circles and test_circles modules, and issuing the following command: python -m unittest test_circles
.
Instructor’s result (it runs the unit test):
Ran 1 test in 0.000s
OK
My result (it seems to execute circles.py
itself):
[yo_scottie_oh@nobara Circles]$ python -m unittest test_circles
Area of circles with r = 2 is 12.566370614359172.
Area of circles with r = 0 is 0.0.
Area of circles with r = -3 is 28.274333882308138.
Area of circles with r = (2+5j) is (-65.97344572538566+62.83185307179586j).
Area of circles with r = True is 3.141592653589793.
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/usr/lib64/python3.11/unittest/__main__.py", line 18, in <module>
main(module=None)
File "/usr/lib64/python3.11/unittest/main.py", line 101, in __init__
self.parseArgs(argv)
File "/usr/lib64/python3.11/unittest/main.py", line 150, in parseArgs
self.createTests()
File "/usr/lib64/python3.11/unittest/main.py", line 161, in createTests
self.test = self.testLoader.loadTestsFromNames(self.testNames,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/unittest/loader.py", line 232, in loadTestsFromNames
suites = [self.loadTestsFromName(name, module) for name in names]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/unittest/loader.py", line 232, in <listcomp>
suites = [self.loadTestsFromName(name, module) for name in names]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/unittest/loader.py", line 162, in loadTestsFromName
module = __import__(module_name)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/yo_scottie_oh/Projects/PythonTutorials/Socratica/Circles/test_circles.py", line 4, in <module>
from circles import circle_area
File "/home/yo_scottie_oh/Projects/PythonTutorials/Socratica/Circles/circles.py", line 14, in <module>
A = circle_area(r)
^^^^^^^^^^^^^^
File "/home/yo_scottie_oh/Projects/PythonTutorials/Socratica/Circles/circles.py", line 6, in circle_area
return pi*(r**2)
~^^~
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
[yo_scottie_oh@nobara Circles]$
I’ve been banging my head against the wall for hours now trying to figure out why when I execute the same command as the instructor, it appears to execute my Python scripts themselves instead of running the unit tests.
Other things I’ve tried:
I’ve read the Python documentation on unit testing. I tried adding this to the end of the test_circles.py document, but that did not change anything.
if __name__ == '__main__':
unittest.main()
I’ve tried following this other written tutorial. After I create the text documents and organize them in the separate shapes and tests folders and run the command python -m unittest discover -v
, again I get a different result from the author.
Author’s result:
test_area (test_circle.TestCircle) ... ok
test_circle_instance_of_shape (test_circle.TestCircle) ... ok
test_create_circle_negative_radius (test_circle.TestCircle) ... ok
test_area (test_square.TestSquare) ... ok
test_create_square_negative_length (test_square.TestSquare) ... ok
test_square_instance_of_shape (test_square.TestSquare) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.002s
OK
My result:
[yo_scottie_oh@nobara test]$ python -m unittest discover -v
test_circle (unittest.loader._FailedTest.test_circle) ... ERROR
test_square (unittest.loader._FailedTest.test_square) ... ERROR
======================================================================
ERROR: test_circle (unittest.loader._FailedTest.test_circle)
----------------------------------------------------------------------
ImportError: Failed to import test module: test_circle
Traceback (most recent call last):
File "/usr/lib64/python3.11/unittest/loader.py", line 419, in _find_test_path
module = self._get_module_from_name(name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/unittest/loader.py", line 362, in _get_module_from_name
__import__(name)
File "/home/yo_scottie_oh/Projects/PythonTutorials/PythonUnitTesting/test/test_circle.py", line 4, in <module>
from shapes.circle import Circle
ModuleNotFoundError: No module named 'shapes'
======================================================================
ERROR: test_square (unittest.loader._FailedTest.test_square)
----------------------------------------------------------------------
ImportError: Failed to import test module: test_square
Traceback (most recent call last):
File "/usr/lib64/python3.11/unittest/loader.py", line 419, in _find_test_path
module = self._get_module_from_name(name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/unittest/loader.py", line 362, in _get_module_from_name
__import__(name)
File "/home/yo_scottie_oh/Projects/PythonTutorials/PythonUnitTesting/test/test_square.py", line 3, in <module>
from shapes.square import Square
ModuleNotFoundError: No module named 'shapes'
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=2)
So yeah… this brings me to my question: What’s the obvious thing that everybody else gets that I’m missing? Is the tutorial outdated? Is it because the instructor is on Windows and I’m on Linux? Why won’t my unit tests run?
When you
import circles
in the test file (even if you only selectcircles_area
) the circles file basically gets executed from top to bottom to run all definitions at the point of the import statement. This executes your for loop which fails, and the actual tests are never run. Just remove that loop in the circles module, and it should work.Yup, gotcha - this was it. Thank you!