Skip to content

Instantly share code, notes, and snippets.

@tasdikrahman
Last active October 31, 2024 10:03
Show Gist options
  • Save tasdikrahman/2bdb3fb31136a3768fac to your computer and use it in GitHub Desktop.
Save tasdikrahman/2bdb3fb31136a3768fac to your computer and use it in GitHub Desktop.
Typical Directory structure for python tests

A Typical directory structure for running tests using unittest

Ref : stackoverflow

The best solution in my opinion is to use the unittest command line interface which will add the directory to the sys.path so you don't have to (done in the TestLoader class).

For example for a directory structure like this:

new_project
├── antigravity.py
└── test_antigravity.py

You can just run:

$ cd new_project
$ python -m unittest test_antigravity

For a directory structure like yours:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

And in the test modules inside the test package, you can import the antigravity package and its modules as usual:

# import the package
import antigravity

# import the antigravity module
from antigravity import antigravity

# or an object inside the antigravity module
from antigravity.antigravity import my_object

Running a single test module:

To run a single test module, in this case test_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

Just reference the test module the same way you import it.

Running a single test case or test method:

Also you can run a single TestCase or a single test method:

$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method

Running all tests:

You can also use test discovery which will discover and run all the tests for you, they must be modules or packages named test*.py (can be changed with the -p, --pattern flag):

$ cd new_project
$ python -m unittest discover

This will run all the test*.py modules inside the test package.

@Ayushverma8
Copy link

Was struggling for this. Thanks. Saved my Day. 👍

@magarage
Copy link

magarage commented Jun 4, 2018

Thanks. I also received help by this 😄 👍

@KevinMendietaP
Copy link

This works also for python3.x ???

@sathiyarajanm
Copy link

great Article btw.

@nosahama
Copy link

nosahama commented Oct 24, 2018

It's not generally ideal to have your tests folder named test so as to prevent any clashes with python inbuilt test, you can also name the project tests folder tests.

Also since the folder would be holding/storing multiple tests, hence the plural naming convention.

@eronekogin
Copy link

Thank you very much for sharing this best practice, I was struggling in the past three hoursT T

@flow2k
Copy link

flow2k commented Apr 25, 2019

@nosahama Are there documentation/links that also recommend your convention? In Java, for example, the test directory is named test, not tests.

@StianHanssen
Copy link

StianHanssen commented Jun 21, 2019

I don't think this is a proper solution.. Sure it works for running the tests, but how do you import modules in the same directory, then?
If I call python antigravity\some_other_file.py or do cd antigravity and then python some_other_file.py and this file imports using any of the methods mentioned, I get ModuleNotFoundError: No module named 'antigravity'.

The only way I found that I could run that file normally would be to do a normal import: import antigravity...But then the tests can't import modules properly.

@felix-hilden
Copy link

felix-hilden commented Jul 3, 2019

@KevinMendietaP - Yes, this does work for Python 3! At least for my particular 3.6.5.
@flow2k - path/to/python/lib/test contains Python's own tests, which is importable as import test. So to avoid clashes one probably should use some other name for a folder containing tests. Or it might not be a problem for you.

@StianHanssen

I don't think this is a proper solution. -- How do you import modules in the same directory, then?

I think that's not really an issue with this particular approach to test discovery as it is one with imports in general. Some time ago I had the pleasure of receiving a rather comprehensive answer on a question on relative imports I posted on Stack Overflow. Building on that, my current approach is to always use absolute imports. That is, even though a shorter import might exist, I always import all the way from the top within a package. Combined with an install via pip install -e ./ this allows for easy development of a package.

Thanks for the Gist by the way! Useful and very much a proper solution in my opinion.

@StianHanssen
Copy link

@felix-hilden Yes, you are correct, I actually found that I was wrong, but forgot to edit my answer.
If you simply run as module instead of as a script it works perfectly fine for both running test and the program it self. To reference to my example, this way would run the program without any problems (calling command from project directory):
python -m antigravity.some_other_file

I was used to running my programs as scripts and so I didn't really consider simply running them as modules. Might be a nice thing to know for others as well!

@eric-burel
Copy link

Edit (question had already been posed):
@StianHanssen your question is very interesting. Is there another alternative to running the code as module?
This feels a bit confusing coming from JS for example where you just import files using realtive path + an index.js...

@StianHanssen
Copy link

StianHanssen commented Nov 8, 2019

@eric-burel
I personally find running code as modules the best alternative because it seems the most consistent :)
Use the import convention shown in this thread and run the program using: python -m antigravity.some_other_file rather than python antigravity\some_other_file.py.
I think a part of the confusion is that your location in the file system when calling the command in terminal affects how things are imported. I always make it a rule to stay in the root directory of the project when running a python file (and run it as a module). That way, it stays consistent and I do not run into troubles with tests and other external modules.

@jpswain
Copy link

jpswain commented Apr 12, 2020

🙏

@clarencedesmarais
Copy link

clarencedesmarais commented Nov 27, 2020

This is great,

Question, do you have an example such that given this directory structure :

image

I want to know how to import src > mypkg > app.py into tests > unit> app_test.py

@kalvelukas
Copy link

@clarencedesmarais : I've got the same problem actually. Could you solve this, or does someone else got a hint for it?

@galak75
Copy link

galak75 commented Jan 8, 2021

@clarencedesmarais, @kalvelukas : you have to configure your setup.py :

setup(
    ...,
    packages=find_packages(where='src'),
    package_dir={
        '': 'src',
    },
    ...
)

Then, you should be able to import mypkg.app

For additional details, take a look at this Stackoverflow question.

@frosk1
Copy link

frosk1 commented Feb 3, 2021

It is really important to mention, that the enduser has to be in the project root directory to perform the unittest method:

cd new_project

refer to this question:
https://stackoverflow.com/questions/49849475/python-unittest-works-from-pycharm-but-not-from-ternimal

@mar-ses
Copy link

mar-ses commented Jul 16, 2021

I've got a follow up question. I named the directory containing the test modules tests as seems to be the convention. However, IPython seems to have its own tests module, which it places into one of the usualy sys.path paths. i.e. for a virtual environment main, created with virtualenv, when I download IPython, the following module clashes:

.../main/lib/python3.6/site-packages/IPython/extensions/tests.py

Since I assume most people install IPython, this sounds incompatible with the convention of calling your testing dir tests. So who is breaking convention here?

@stephenhutch
Copy link

Why does this not find any tests with the above:

$ python -m unittest tests

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

@samyouaret
Copy link

You need to add __init__.py to the tests directory, If you have other subdirectories in the tests directory you also need to add the __init__.py so python can know that those are modules, not just directories.

then run:

python3 -m unittest discover -p 'test_*.py'

@10cheon00
Copy link

10cheon00 commented Sep 26, 2022

Adding __init__.py into tests/APPS_NAME/ is working! 👍

my test folder structure

root
+-- config
+-- mysite
|   `-- models, views, urls...
`-- tests
    `-- mysite
        +-- __init__.py
        +-- tests_models.py
        `-- other tests...

Thanks @samyouaret

@samyouaret
Copy link

you are welcome @10cheon00 .

@mrdougwright
Copy link

This was so very helpful. Thank you. 🎉

@paulied67
Copy link

This is great,

Question, do you have an example such that given this directory structure :

image

I want to know how to import src > mypkg > app.py into tests > unit> app_test.py

What if, in this example, app.py contains the following import: import view? I find that the test fails trying to import view.py:

ModuleNotFoundError: No module named 'view'

It's almost as if the directory the test is run in becomes the "current relative" directory and, because app.py is being imported from a test, ie app_test.py, that the imports are expected from the test's location and not the location of the file importing the module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment