4

I want to execute unittests for my project. Inside the project root, I use a src folder for my code and a tests folder for my unittests. This is my project structure:

project/
│
├── src/
│   └── func.py
|
└── tests/
    ├── __init__.py
    └── test.py

Content of func.py:

def func():
    return True

Content of test.py:

import unittest

target = __import__("func.py")
func = target.func

class TestFunc(unittest.TestCase):
    def test_func(self):
        self.assertTrue(func())

if __name__ == '__main__':
    unittest.main()

At the moment, I do not want to provide my code as a module. That's why there is no __init__.py inside src and I import my code to test via __import__().

If I execute my unittests via python -m unittest discover -s tests -t src in PowerShell, I get the following error message:

PS C:\Users\username\Desktop\project> python -m unittest discover -s tests -t src
Traceback (most recent call last):
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\__main__.py", line 18, in <module>
    main(module=None)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\main.py", line 100, in __init__
    self.parseArgs(argv)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\main.py", line 124, in parseArgs
    self._do_discovery(argv[2:])
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\main.py", line 244, in _do_discovery
    self.createTests(from_discovery=True, Loader=Loader)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\main.py", line 154, in createTests
    self.test = loader.discover(self.start, self.pattern, self.top)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\loader.py", line 349, in discover
    tests = list(self._find_tests(start_dir, pattern))
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\loader.py", line 387, in _find_tests
    name = self._get_name_from_path(start_dir)
  File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\unittest\loader.py", line 371, in _get_name_from_path
    assert not _relpath.startswith('..'), "Path must be within the project"
AssertionError: Path must be within the project

If I understand this tutorial correctly, it should work. So, what am I doing wrong?

stackprotector
  • 10,498
  • 4
  • 35
  • 64

2 Answers2

5

After zardosht pointed out the cause of the failure in his answer, I found this answer and changed my project to this:

project/
│
├── src/
│   ├── __init__.py
│   └── func.py
|
└── tests/
    ├── __init__.py
    └── test.py

Content of func.py:

def func():
    return True

Content of test.py:

import unittest

from src.func import func

class TestFunc(unittest.TestCase):
    def test_func(self):
        self.assertTrue(func())

if __name__ == '__main__':
    unittest.main()

Then, I was able to run my tests successfully from the project root simply by issuing:

python -m unittest

I might want to change some names now, but here, I will keep the original ones for better comparison.


The commands

python -m unittest discover -s tests

and

python -m unittest discover -s tests -t .

would also work, but not

python -m unittest discover -s tests -t src

because what you specify with -s, has to be contained in what you specify with -t.

stackprotector
  • 10,498
  • 4
  • 35
  • 64
1

I think the issue is with the test discovery.

... all of the test files must be modules or packages (including namespace packages) importable from the top-level directory of the project ...

You are specifying src as the top-level directory (python -m unittest discover -s tests -t src) and the tests are not importable in the src directory.

zardosht
  • 3,014
  • 2
  • 24
  • 32