Python versions are fairly compatible so you don't have to test each and every minor version. Instead:
- Test the minimal version you are going to support, e.g. CPython 3.5.
- Test the latest version, e.g. CPython 3.7.
- Possibly, test another Python implementation like PyPy 3.7.
- If you support Python 2.7, test that separately – but note that 2.7 will reach its EOL in 2020, so there is little sense for a new project to support it.
The minimal version you're going to support is a decision you have to make – don't just see which version your code happens to run under. Each new version improves the language (e.g. with new features such as type annotations, async functions, f-strings, ordered dicts, …) and improves the standard library. So take a moment to consider what the minimal level is that you're going to support. In particular, trying to write code that is both valid Python 2.7 and 3.x can be very difficult when considering new syntax features or the different meanings of
For an open source projects, you can easily use cloud-based CI services to do this – one build job for each tested Python version.
For local testing, I personally manually switch between the 2.7 and 3.6 Python versions that are provided by my operating system, using a virtualenv for each with the proper packages. Other people use Tox to run tests across multiple versions, which helps manage the virtualenvs automatically.
Docker based tests take a bit more setup but are still comparatively easy to do. In particular, they make it easy to test across different Python versions without having to install them on your main OS. In my experience, I prefer to have my main development setup outside of Docker so that I can strike the “build” part from the edit–build–test cycle. Docker may be appropriate for CI tests, or if your software has difficult to install dependencies.