Automated Testing
These notes will cover how to start a brand new Python project from scratch, initialize a Git repository inside of it, and how to configure the repository to automatically test all your code every time you push to Gitlab. This will be assumed you have some familiarity with the Python programming language, and Git version control system. The tutorial will be broken up into two parts, the first covering how to configure a new project in Python, complete with unit tests, and a second part covering how to make Gitlab automatically run your test scripts every time a change is pushed to your remote repository.
NOTE: For brevity this tutorial is only covering how to do testing in Python, but much of the Gitlab Runner stuff is language agnostic and can be easily applied to your language of choice
Requirements
Creating a New Project
We are going to use Poetry to create a new Python Project. I chose Poetry because it does a number of things to make dependecy management in Python much simpiler. It is still a work in progress and some aspects of it are slow but overall it provides a very low barrier of entry for adhearing to some best practices, such as virtual environments, project structuring, depedency tracking, and unit tests.
The following will be done from a Bash terminal on a machine running Linux. You will need to make changes to it for your specific OS. If you are running Windows I HIGHLY!! HIGHLY!! Recommend you at least install and setup Windows Sub-system for Linux (WSL)… or just switch to Linux :-)
|
|
Notice that poetry
will create a number of directories and some files. This folder structure is generally accepted to be a best practice in Python. More information on how to
use Poetry with an existing code base can be found on the Poetry website.
|
|
Init Git Repository
Once our project is created we can go ahead and initialize our Git repository. I suggest adding a .gitignore
starter files can be found here.
|
|
Add Python Code
Now that we have created the scafolding for our Python project and initilized the Git repo lets add some code. The following code is nothing special, just something I threw together quickly in order to be an example for testing. Either create a file containing the code below or feel free to use your own code.
|
|
Add Test Code
Testing is critical to having good dependable code. Test driven design principles say that we should never write code unless we are writing it to pass a test case.
Realistically this might not always happen, but either way we need to have some tests setup so we know if our code is doing what we say it should be doing. Copy
the following code into your project or write your own tests. A good strategy for organizing your tests is to create one test file per normal file. I generally
keep all my tests stored in a ./tests/
directory and follow the pattern of <real_code>.py
and test_<real_code>.py
.
Pytest is my prefered method for testing in Python, but there are other ways and you don’t even have to use a package, but it can make things simiplier. Again for brevity sake this tutorial will not go into great detail on all the different features of pytest but rather just showcase some practical examples.
Key Points
- Only have to do
import pytest
in your test file. - To test your code make an assertion that your code does what you say it should, and thats it.
- Snapshot testing is good for tracking how changes in code effect your data… just do
import snapshottest
. - To run your tests using Poetry you can do
poetry run pytest
and it will run the tests and provide you with the results
Options Reference
-x
stops on first failure-v -vv -vvv
various levels of verbousness-k "<part of test name>"
run a specific test(s) aka Key word expression-cov=<module to test> <tests>
get coverage report
|
|
PyProject File
Just to make sure all dependecies are met for this project here is the pyproject.toml
file I was using.
|
|
Create Gitlab Runner Script
Gitlab will start a “Runner” whenever a repository has a .gitlab-ci.yml
file present. You can think of the yaml file as kind of a cross between a Dockerfile and a docker-compose file (If you don’t know what either of those are then just think of it as a script that will create a virtual environment for your project).
The file lets you instantiate a single docker container or a series of them to run your code. The computer resources used to run the container are either shared resources belonging to
Gitlab or you can create a Local Runner on your own hardware. Creating a Local Runner is outside the scope of this tutorial but this method would allow for test containers to have access
to large or senstive files.
The Parts of the YAML File
- Image: The Docker Image you want Gitlab to run things on.
- Stages: List out the names of the stages you want Gitlab to run for you (ie. Build, Test, Deploy).
- Before Script: Any scripting that needs to be done to prep your environment ahead of time
- Stage Section:
- Build Definition: All the steps that need to be done to build your project. Not so important for Python… more relevant for a compiled language
- Test Definition: The steps required to run Pytest or any other testing your project requires.
- Deploy Definition: You got here so your code is probably production ready..so lets push it to a Repository or what ever place is should go in order to be put into production.
Minimal Example Yaml File
|
|
More Advanced Example NOTE: This is still a work in progress but it does work as it was adapted from an issue on the Poetry GitHub
|
|
Build a Docker Image Example NOTE: This is also still under development but the basics are here
|
|