Hello, I’m trying to use pytest to test a module, but it keeps giving me an import error:
ImportError while importing test module ‘/home/roberto-padilla/projects/ex47/tests/ex47_test.py’.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib/python3.12/importlib/init.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/ex47_test.py:2: in
from ex47.game import Room
E ModuleNotFoundError: No module named ‘ex47.game’
Also, here is the code for ex47_test.py that asks to import game.py:
from pytest import *
from ex47.game import Room
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grab. There's a
door to the north.""")
assert gold.name, "GoldRoom"
assert gold.paths, {}
def test_room_paths():
center = Room("Center", "Test room in the center.")
north = Room("North", "Test room in the north.")
south = Room("South", "Test room in the south.")
center.add_paths({'north': north, 'south': south})
assert center.go('north'), north
assert center.go('south'), south
def test_map():
start = Room("Start", "You can go west and down a hole.")
west = Room("Trees", "There are trees here, you can go east.")
down = Room("Dungeon", "It's dark down here, you can go up.")
start.add_paths({'west': west, 'down': down})
west.add_paths({'east': start})
down.add_paths({'up': start})
assert start.go('west'), west
assert start.go('west').go('east'), start
assert start.go('down').go('up'), start
I tried what you said and pytest gave me three errors. I also tried this according to Medium and the line works but pytest still gives me one error (an import error):
What you just typed is when you’re implementing relative imports. Note when you’re using relative imports, Python does not allow you to open a lower level module and run it as a standalone module. In your case, you wouldn’t be able to open the module ex47_test.py and hit run. It would give you an error. If you’re implementing relative imports, you have to implicitly run the lower level module from the main package module (script). Please take that into consideration when you’re implementing your packages.
In any case, can you try:
from pytest import *
import os, sys
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
from game import Room # Since I am assuming that you did not modify your original script
Can you try this?
If you still get errors, copy and paste it here so that we can analyze it.
I tried what you said with the exception of the line:
from game import Room
and pytest gave me three errors. This time it’s better than before! I only had one error.
=================================== FAILURES ===================================
__________________________________ test_room ___________________________________
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grab. There's a
door to the north.""")
assert gold.name, "GoldRoom"
> assert gold.paths, {}
E AssertionError: {}
E assert {}
E + where {} = <game.Room object at 0x7cebc39500b0>.paths
tests/ex47_test.py:15: AssertionError
=============================== warnings summary ===============================
../../.venvs/lpthw/lib/python3.12/site-packages/_pytest/terminal.py:113
/home/roberto-padilla/.venvs/lpthw/lib/python3.12/site-packages/_pytest/terminal.py:113: PytestCollectionWarning: cannot collect test class 'TestShortLogReport' because it has a __new__ constructor (from: tests/ex47_test.py)
class TestShortLogReport(NamedTuple):
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/ex47_test.py::test_room - AssertionError: {}
==================== 1 failed, 2 passed, 1 warning in 0.17s ====================
from pytest import *
import os, sys
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
from game import Room
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grab. There's a
door to the north.""")
assert gold.name, "GoldRoom"
assert gold.paths, {}
def test_room_paths():
center = Room("Center", "Test room in the center.")
north = Room("North", "Test room in the north.")
south = Room("South", "Test room in the south.")
center.add_paths({'north': north, 'south': south})
assert center.go('north'), north
assert center.go('south'), south
def test_map():
start = Room("Start", "You can go west and down a hole.")
west = Room("Trees", "There are trees here, you can go east.")
down = Room("Dungeon", "It's dark down here, you can go up.")
start.add_paths({'west': west, 'down': down})
west.add_paths({'east': start})
down.add_paths({'up': start})
assert start.go('west'), west
assert start.go('west').go('east'), start
assert start.go('down').go('up'), start
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grab. There's a
door to the north.""")
assert gold.name, "GoldRoom"
# assert gold.paths, {}
The object Room from the module game is what I am referring to. Apparently, this:
gold.paths is False
Note that the assert keyword will only raise an exception if the conditional statement is False. If it is True, it skips the assert keyword.
I don’t know the purpose of the { } curly braces to be honest as an assignment does not take place for either a True or a False condition. Check your reference for creating this script and what did the authors have in mind for them.
You can try running the examples in the tutorial link that I provided as well as this example:
assert 3 < 4 , {} # "Three is less than four."
assert 3 > 4 , {} # "3 is not greater than four."
After running it, note the message that is raised. It only raises an assertion when the conditional is False.
So that it does not crash your program, you can always "catch" the assertion with a try / except combination. Play around with it to understand its behavior.
As a quick test, first run this:
assert 3 > 4 , {} # "3 is not greater than four."
then run this to compare:
try:
assert 3 > 4 , {} # "3 is not greater than four."
except AssertionError:
print('Less than error.')
Note that when you wrap it with the try / except combination, it keeps your program from crashing by catching the exception. Nice trick to consider.