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"
Asked By: normanius

||

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 ===========================
Answered By: larsks

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
Answered By: normanius
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.