[TIP] PyTest test directory structure confusion
Brian Okken
variedthoughts at gmail.com
Wed Aug 28 08:11:37 PDT 2019
If you have all of your tests under a "tests" directory separate from your
source code, you generally don't need __init__.py files.
The pytest book goes into more detail about it in chapter 6 under the
section "Avoiding Filename Collisions".
If you have two test files, or think you might someday, that are the same
name in different subdirectories, then the __init__.py technique is useful
to remove the collision.
These files are empty.
So, under simple cases, you don't need __init__.py files.
If you have them, they won't hurt, and might help.
Hope this helps.
- brian
- Brian
On Wed, Aug 28, 2019 at 4:52 AM Marius Gedminas <marius at gedmin.as> wrote:
> Hi!
>
> On Tue, Aug 27, 2019 at 09:45:27PM -0700, Tony Cappellini wrote:
> > I’m new to using PyTest. I’ve got a very simple python file, and a very
> simple
> > test file for it.
> ...
>
> > I’ve been having a problem getting a unittest to be able to access the
> file
> > it’s trying to test. I’m sure that I don’t have the correct directory
> > configuration, but at the same time, I’m not sure what the correct
> directory
> > configuration should be though.
>
> You have the simplest possible case: one code file, one test file. You
> don't need a directory structure at this point, just the two files:
>
> mycode.py
> tests.py
>
> inside your tests.py you can do
>
> import mycode
>
> def test_my_stuff():
> assert mycode.stuff(42) == 25 # etc.
>
> and you should be able to run the tests with
>
> pytest tests.py
>
> If you don't want to keep repeating 'tests.py' on the command line,
> create a pytest.ini with
>
> [pytest]
> testpaths = tests.py
>
> and then you can run just
>
> pytest
>
> That's it!
>
> I use this structure for a few of my small Python projects, e.g.
> https://github.com/mgedmin/ghcloneall
>
>
> > Page 25 of “Python Testing with PyTest refers to __init__.py files in
> the same
> > directory as the test files themselves.
> >
> > Under Project Structure, This website
> > [1]https://automationpanda.com/2017/03/14/python-testing-101-pytest/
> >
> > states that __init__.py files should NOT be in the same directory as the
> test
> > files.
>
> I've no idea why that page makes this claim. I have my tests in a
> package in https://github.com/mgedmin/pyspacewar, and pytest has no
> trouble with that structure.
>
> > __init__.py files have always been the biggest headache for me, as I’ve
> never
> > been able to find a clear reference as to what should or shouldn’t be in
> those
> > files.
> > Why is it that some are empty, while others have tons of imports?
>
> I assume you know what they're for? If not, see the Python Tutorial
> section on packages:
> https://docs.python.org/3/tutorial/modules.html#packages
>
> As for the contents, the short answer is: if you're not sure, keep
> __init__.py files empty. But if you feel like you want to put some code
> in there, there likely won't be any harm.
>
> > I would appreciate if someone could provide a reference as to how a
> PyTest
> > project should be structured, where __init__ files should and shouldn’t
> be,
> > along with their contents (if any).
>
> There's more than one common source layout, and which is best is a
> matter of opinion.
>
>
> The one I'm used to has a 'src/' directory at the top, and puts all the
> tests as subpackages inside the actual code tree. Like, imagine if the
> example I gave before grew and grew and became too big for a single
> source file:
>
> mycode.py
> tests.py
> pytest.ini
> setup.py
> tox.ini
>
> I've added a setup.py because you probably want to be able to pip
> install the thing, and pull it any dependencies it has. I've added a
> tox.ini because tox is a wonderful tool for automating the tests -- it
> creates virtualenvs for you so you get all the code and test
> dependencies without polluting your global Python installation and
> interfering with other projects.
>
> (For completeness, here's what a setup.py looks:
>
> from setuptools import setup
> setup(
> name='mycode',
> version=...,
> author=...,
> license=...,
> url=...,
> description=...,
> long_description=...,
> py_modules=['mycode'],
> )
>
> and here's tox.ini:
>
> [tox]
> envlist = py37
>
> [testenv]
> deps = pytest
> commands = pytest {posargs}
>
> )
>
> So, at this point splitting the code into several modules will result in
>
> src/
> mycode/
> __init__.py # maybe empty, maybe not
> things.py
> more_things.py
> tests/
> __init__.py # empty file
> test_mycode.py
> test_things.py
> test_more_things.py
> pytest.ini
> setup.py
> tox.ini
>
> Here each code module has a corresponding test module, for my own
> convenience: when I want to find the unit tests for a function
> mycode.things.do_x(), I'll know to look in mycode.tests.test_things
> for test functions called test_do_x (with optional suffixes if there's
> more than one test).
>
> To make this work, pytest.ini changes from
>
> [pytest]
> testpaths = tests.py
>
> to
>
> [pytest]
> testpaths = src
>
> and you can't run 'pytest' without arguments any more (because ./src is
> not in PYTHONPATH -- this is the downside of using a top-level 'src'
> subdirectory), but you can run 'tox' without arguments. tox.ini is
> unchanged, setup.py changes from using
>
> from setuptools import setup
> setup(
> ...
> py_modules='mycode',
> )
>
> to
>
> from setuptools import setup, find_packages
> setup(
> ...
> packages=find_packages('src'),
> package_dir={'': 'src'},
> )
>
> Now, if you want to continue to write code like
>
> from mycode import stuff
>
> then mycode/__init__.py will have to define the 'stuff' function, or
> import and re-export it like this:
>
> # mycode/__init__.py
> from .things import stuff # reexport
>
> But if you're fine requiring that all users of mycode change their code
> to do
>
> from mycode.things import stuff
>
> then mycode/__init__.py can be an empty file.
>
>
> Hope that helped!
>
> Marius Gedminas
> --
> /*
> * The lockdep graph lock isn't locked while we expect it to
> * be, we're confused now, bye!
> */
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.idyll.org/pipermail/testing-in-python/attachments/20190828/77d798e7/attachment-0001.htm>
More information about the testing-in-python
mailing list