Python unittest: How to assert the existence of a file or folder and print the path on failure?
Question:
In a python test case
, I would like to assert the existence of a file or folder AND provide a useful error message in case the assertion fails. How could I do this?
The following of course works, but it does not yield the path/filename in the error message:
import unittest
import pathlib as pl
class TestCase(unittest.TestCase):
def test(self):
# ...
path = pl.Path("a/b/c.txt")
self.assertTrue(path.is_file())
self.assertTrue(path.parent.is_dir())
if __name__ == "__main__":
unittest.main(verbosity=2)
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
self.assertTrue(path.is_file())
AssertionError: False is not true
In a larger test it can be beneficial to see at a glance for which file the assertion failed. How to extend unittest.TestCase
to print a better assertion message for such a test?
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
self.assertFileExists(path)
AssertionError: File does not exist: "a/b/c.txt"
Answers:
You could write your tests so that the assertion includes the pathname:
import unittest
import pathlib as pl
class TestCase(unittest.TestCase):
def test(self):
# ...
path = pl.Path("a/b/c.txt")
self.assertEqual((str(path), path.is_file()), (str(path), True))
if __name__ == "__main__":
unittest.main(verbosity=2)
Which would give you output like:
======================================================================
FAIL: test_something (__main__.TextExample)
----------------------------------------------------------------------
Traceback (most recent call last):
File "testfoo.py", line 8, in test_something
self.assertEqual((path, path.is_file()), (path, True))
AssertionError: Tuples differ: (PosixPath('path/to/file'), False) != (PosixPath('path/to/file'), True)
First differing element 1:
False
True
- (PosixPath('path/to/file'), False)
? ^^^^
+ (PosixPath('path/to/file'), True)
? ^^^
But you could also just decide to use pytest
instead, and write your test like this:
from pathlib import Path
def test_something():
path = Path('path/to/file')
assert path.is_file()
Running that with pytest
will include the path in your failures automatically:
============================= test session starts ==============================
platform linux -- Python 3.7.5, pytest-4.6.6, py-1.8.0, pluggy-0.13.0
rootdir: /home/lars/tmp
collected 1 item
testfoo.py F [100%]
=================================== FAILURES ===================================
________________________________ test_something ________________________________
def test_something():
path = Path('path/to/file')
> assert path.is_file()
E AssertionError: assert False
E + where False = <bound method Path.is_file of PosixPath('path/to/file')>()
E + where <bound method Path.is_file of PosixPath('path/to/file')> = PosixPath('path/to/file').is_file
testfoo.py:6: AssertionError
=========================== 1 failed in 0.01 seconds ===========================
Extending unittest.TestCase
with an additional assertion worked best for me.
import unittest
import pathlib as pl
class TestCaseBase(unittest.TestCase):
def assertIsFile(self, path):
if not pl.Path(path).resolve().is_file():
raise AssertionError("File does not exist: %s" % str(path))
class ActualTest(TestCaseBase):
def test(self):
path = pl.Path("a/b/c.txt")
self.assertIsFile(path)
This yields:
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
raise AssertionError("File does not exist: %s" % str(path))
AssertionError: File does not exist: a/b/c.txt
In a python test case
, I would like to assert the existence of a file or folder AND provide a useful error message in case the assertion fails. How could I do this?
The following of course works, but it does not yield the path/filename in the error message:
import unittest
import pathlib as pl
class TestCase(unittest.TestCase):
def test(self):
# ...
path = pl.Path("a/b/c.txt")
self.assertTrue(path.is_file())
self.assertTrue(path.parent.is_dir())
if __name__ == "__main__":
unittest.main(verbosity=2)
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
self.assertTrue(path.is_file())
AssertionError: False is not true
In a larger test it can be beneficial to see at a glance for which file the assertion failed. How to extend unittest.TestCase
to print a better assertion message for such a test?
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
self.assertFileExists(path)
AssertionError: File does not exist: "a/b/c.txt"
You could write your tests so that the assertion includes the pathname:
import unittest
import pathlib as pl
class TestCase(unittest.TestCase):
def test(self):
# ...
path = pl.Path("a/b/c.txt")
self.assertEqual((str(path), path.is_file()), (str(path), True))
if __name__ == "__main__":
unittest.main(verbosity=2)
Which would give you output like:
======================================================================
FAIL: test_something (__main__.TextExample)
----------------------------------------------------------------------
Traceback (most recent call last):
File "testfoo.py", line 8, in test_something
self.assertEqual((path, path.is_file()), (path, True))
AssertionError: Tuples differ: (PosixPath('path/to/file'), False) != (PosixPath('path/to/file'), True)
First differing element 1:
False
True
- (PosixPath('path/to/file'), False)
? ^^^^
+ (PosixPath('path/to/file'), True)
? ^^^
But you could also just decide to use pytest
instead, and write your test like this:
from pathlib import Path
def test_something():
path = Path('path/to/file')
assert path.is_file()
Running that with pytest
will include the path in your failures automatically:
============================= test session starts ==============================
platform linux -- Python 3.7.5, pytest-4.6.6, py-1.8.0, pluggy-0.13.0
rootdir: /home/lars/tmp
collected 1 item
testfoo.py F [100%]
=================================== FAILURES ===================================
________________________________ test_something ________________________________
def test_something():
path = Path('path/to/file')
> assert path.is_file()
E AssertionError: assert False
E + where False = <bound method Path.is_file of PosixPath('path/to/file')>()
E + where <bound method Path.is_file of PosixPath('path/to/file')> = PosixPath('path/to/file').is_file
testfoo.py:6: AssertionError
=========================== 1 failed in 0.01 seconds ===========================
Extending unittest.TestCase
with an additional assertion worked best for me.
import unittest
import pathlib as pl
class TestCaseBase(unittest.TestCase):
def assertIsFile(self, path):
if not pl.Path(path).resolve().is_file():
raise AssertionError("File does not exist: %s" % str(path))
class ActualTest(TestCaseBase):
def test(self):
path = pl.Path("a/b/c.txt")
self.assertIsFile(path)
This yields:
======================================================================
FAIL: test (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "my_test.py", line 194, in test
raise AssertionError("File does not exist: %s" % str(path))
AssertionError: File does not exist: a/b/c.txt