由 neevop 七月 3, 2023
testing file writes with pytest
consider a simple class with one or more methods for file write/access
from pathlib import Path
class UnderTest:
def __init__(self, basedir=None):
self.BASE_DIR = basedir or Path(__file__).parents
def save_log(self):
with open(self.BASE_DIR / "log-file.log", "a") as logfile:
logfile.write("a dummy line")
test for it
# with the tmp_path fixture we have access to a temporary path in pytest once we can write, read, and assert over
def test_it_writes_to_log_file(tmp_path):
under_test = Undertest(basedir=tmp_path)
under_test.save_log()
file = tmp_path / "log-file.log"
assert file.read_text() == "a dummy line"
mocking command line arguments with monkeypatch
suppose we add argument parsing to our class, which now become alse a CLI tool
import argparse
from pathlib import Path
class UnderTest:
def __init__(self, basedir=None):
self.BASE_DIR = basedir or Path(__file__).parents
def _parse(self):
ap = argparse.ArgumentParser()
ap.add_argument("-n", "--name", required=True, help="Name of the log file")
self.args = vars(ap.parse_args())
def save_log(self):
with open(self.BASE_DIR / "log-file.log", "a") as logfile:
logfile.write("a dummy line")
if __name__ == "__main__":
x = UnderTest()
x.save_log()
to make our tests pass, we need to mack sys.args
. For this we can use monkeypatch
, another pytest fxture, which is particularly useful for mocking and patching object.
def test_it_writes_to_log_file_from_command_line_arg_(monkeypatch, tmp_path):
monkeypatch.setattr("sys.argv", ['pytest', '--name', 'logfilename.log'])
# test as usual here
under_test = UnderTest(basedir=tmp_path)
under_test.save_log()
file = tmp_path / "logfilename.log"
assert file.read_text() == "a dummy line"
applying fixture to every test function
when we need to patch something in our code, and this “something” must be patched inside every test function, we declare a custom fixture with @pytest.fixture
and autouse
import pytest
from package.core import UnderTest # package under test
@pytest.fixture(autouse=True)
def mock_args(monkeypatch):
monkeypatch.setattr("sys.argv", ['pytest', '--name', 'logfilename.log'])
def test_it_writes_to_log_file(tmp_path):
under_test = UnderTest(basedir=tmp_path)
under_test.save_log()
file = tmp_path / logfilename.log
assert file.read_text() == "a dummy line"
printing print() outputs in testing
sometime we need to take a quick lookl at a variable in code, and put a print()
somewhere. By default pytest suppresses this kind output. To see it during a test, run pytest with the -s
flag
pytest -s