I don't know very well Python but you are right to ask yourself the question
as separating test and application code makes part of good practice to have a robust/reliable application and tests.
The pytest
(a known test framework for Python) documentation explains in its best practice guide the two ways (separating and not separating the test code from the application).
Here is the part referencing the isolated layout :
Choosing a test layout / import rules
pytest supports two common test layouts:
Tests outside application code
Putting tests into an extra directory outside your actual application
code might be useful if you have many functional tests or for other
reasons want to keep tests separate from actual application code
(often a good idea):
setup.py
mypkg/
init.py
app.py
view.py
tests/
test_app.py
test_view.py
...
This way your tests can run easily against an installed version of
mypkg.
Note that using this scheme your test files must have unique names,
because pytest will import them as top-level modules since there are
no packages to derive a full package name from. In other words, the
test files in the example above will be imported as test_app and
test_view top-level modules by adding tests/ to sys.path.
If you need to have test modules with the same name, you might add
init.py files to your tests folder and subfolders, changing them to packages:
setup.py
mypkg/
...
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py
Now pytest will load the modules as tests.foo.test_view and
tests.bar.test_view, allowing you to have modules with the same name.
But now this introduces a subtle problem: in order to load the test
modules from the tests directory, pytest prepends the root of the
repository to sys.path, which adds the side-effect that now mypkg is
also importable. This is problematic if you are using a tool like tox
to test your package in a virtual environment, because you want to
test the installed version of your package, not the local code from
the repository.
In this situation, it is strongly suggested to use a src layout where
application root package resides in a sub-directory of your root:
setup.py
src/
mypkg/
init.py
app.py
view.py
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py
This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this
excellent blog post by Ionel Cristian Mărieș.
https://docs.pytest.org/en/latest/goodpractices.html