How we made the AWS serverless ecommerce platformsample have working unit tests.
In (Python) monorepo setups, running Unit-tests is often more difficult than it should be. In this blog post, we examine how we enabled the ecommerce-platform ( ) monorepo to run unit tests directly in vscode and PyCharm. This can be seen in several places on the web.
Developing our Insight Platform, we’re working on a bunch of microservices, based on AWS Lambda, written in Python. Some time ago, we decided to move to a monorepo for this purpose, which we based on the above-mentioned serverless-ecommerce-platform sample form AWS.
The ecommerce example project has a tests/ folder in each microservice - and each lambda “on its own” with regards to the python path/environment, so no common python environment (or module tree) across the whole project. Each lambda manages its own dependencies (with a separate requirements.txt)
So, a typical microservice looks like this:
service/ src/ lambda1/ lambda1_handler.py requirements.txt libs/ service_libs/ lib.py tests/ unit/ hopefully_many_tests.py shared/ tests/ unit/ common_modules.py
While this is great for writing and executing a single lambda, it has some drawbacks: We can’t use standard python testing tooling. pytest on the root level doesn’t work anymore for example, because there is no complete python path. Executing from the make files of each service work by tightly controlling the (python-)path and environment variables - but this didn’t translate into IDEs.
As this was a story of little documentation and many wrong ways, this post tries to summarize our findings and explain the code that can be found in our fork of the samples project: We enabled this for the two most common IDEs in our team (discounting the vim group, sorry) - JetBrains PyCharm and Microsofts VSCode.
Setup in PyCharm
Pycharm has a nifty test-runner, showing you all tests with their respective output and being able to re-run failed tests - but by default, it was useless for the ecommerce sample. Running any tests fails because of (python) path issues; the same is true for running the whole project.
To see where we needed to go, we started to dissect the Makefiles and script in tools/tests-unit. With a bunch of path logic, make tests-unit-service boils down to running pytest on a specific path, starting “in the service directory” with specific environment variables and an optimized PYTHON_PATH. After we got this replicated in the CLI, it was easy to write an Intelij run-config for a single service:
This worked well but doesn’t scale, having to create a (manual) run-config per service. Our requirements:
- Pass on system variables from the current shell to the test runner
- Have the tests run in the current “service” working directory
- Run the build before the unit-tests
None of this was working out of the box sadly, so in the end, we solved it with a special Makefile script that creates a bunch of run-configs for our projects. JetBrains advises against this, but this was by far the easiest solution.
You can find the code in this commit
As far as this journey goes, MS VSCode was much harder to get started than PyCharm. Opening up the above-described monorepo, you find that test discovery just plain doesn’t work. In this case, VSCode does too much IMHO: Instead of asking you to configure the tests, it tries to autodetect them by running the package steps of the configured test runner and “reading” the console output. Which is really nice for simple projects, but breaks horribly in this larger setup.
Based on this blog, the solution is the vscode Workspace feature. Defining a workspace folder per service already makes test discovery work again - but the tests don’t run yet.
To get those to work, all the arguments & path settings need to be defined, as above in PyCharm. The simplest way we found for this was to be done once in the .workspace file, linking to a .env file that controls the Environment variables. Because the paths could be specified relative, a single set of these instructions was enough to enable all services.
The code can be found in this commit
With these workarounds, the “testing” tab works, the auto-discovery does it’s magic - and tests can be debugged in VScode.
The only thing we’ve not been able to get working: Executing the build before the unit tests run seems to be a bit more difficult in VSCode - for the time being, that’s still a manual process.
Writing tests should be painless and a boon, not a chore. Running & debugging the tests directly in the IDE is an important puzzle piece towards that - one that was often disallowed in larger setups. Hopefully, this writeup clarifies the process of how to enable the in-IDE testing in larger setups clearer and easier to replicate.