Automate Tests With GitHub Actions for Python
Tags: python, testing, github, devops
Published: 2021-03-26 06:16:44

Since the addition of GitHub Actions, a lot of things, that previsouly we had to use third party services for, have become easier. Recently, an user raised an issue in my [downloader-cli](https://github.com/deepjyoti30/downloader-cli) repository. He suggested that addition of tests would be greatly helpful. More importantly because that way when people make a PR, the tests would tell the developers if the PR can be accepted.

So, I decided to add some nice tests for my app. `downloader-cli` is written in Python and it is a small, simple, downloader library that features a highly customizable, responsive progressbar for the commandline.

## How will it work

The idea is simple. We will add a GitHub workflow file. This file will have the details as to when and what to do. For the sake of this example, I will make the tests run when a push is made to the `master` branch or a pull request is made to the `master` branch.

In case you don't already know, GitHub's workflow files are written in [YAML](https://yaml.org/) and are pretty simple to get started with.

You just need to create a directory named `.github` and a subdirectory inside that named `workflows`. Inside the subdirectory, you can add as many workflow files as you want, given that all of them follow proper syntax and are written in **YAML**.

## Adding Conditions to run

We will create a file named `tests.yml` and add the basic conditions to make it run on PR's and Pushes.

```yaml
name: Run tests

on:
  push:
    branches:
      - "master"
  pull_request:
    branches:
      - "master"
```

The above code does the following:

- Add condition to run on `push` on branch `master`
- Add condition to run on `pull_request` on branch `master`

## Add the job

So once we tell GitHub about when to run the action, we also need to pass them some commands on what to do when running the action. These can be called as `jobs`. One action file can have multiple jobs and jobs can depend on other jobs so that they will run only after the job they depend on is run.

```yaml
jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        # Run in all these versions of Python
        python-version: [3.5, 3.6, 3.7, 3.8, 3.9]

    steps:
        # Checkout the latest code from the repo
      - name: Checkout repo
        uses: actions/checkout@v2
        # Setup which version of Python to use
      - name: Set Up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
        # Display the Python version being used
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"
        # Install the package using the setup.py
      - name: Install package
        run: python setup.py install
        # Install pytest (you can use some other testing utility)
      - name: Install pytest
        run: |
          python -m pip install --upgrade pip
          pip install pytest
        # Run the tests. I'm using pytest and the file is in the tests directory.
      - name: Run tests
        run: pytest tests/test*
```

In the above code, we add a job with the name `test`.

- This job `runs-on` the latest Ubuntu Version as deonoted by `ubuntu-latest`.
- We are using the `matrix` strategy to run it for different python versions.


Then we have added a few steps. The steps do the following:

- Checkout the latest code from the repo
- Setup the `python-version` as passed by the matrix strategy.
- Display the python version (just cross check).
- Install the package. (In my case it is using the `setup.py` file.)
- Install `pytest`.
- Run the tests.

## Push the code

Once you have the file setup, you can try try out the changes by pushing the code to the master branch.

Just do a push using `git` and go to GitHub and open the `Actions` tab. You will see a job running with the yellow indicator on the left. (The yellow means it is running).

## Conclusion

If you want to take a look at the actions of my repo, you can [check them here](https://github.com/deepjyoti30/downloader-cli/actions).

Also, GitHub Actions can be used for various automations. Most useful usecase (at least for me) being the ability to add CI/CD pipelines which have made a lot of my deployments painless. You can see an example of that [in my ytmdl-web repo](https://github.com/deepjyoti30/ytmdl-web-v2/blob/master/.github/workflows/build-push.yml).

Also, in case you want to take a look at the file from my `downloader-cli` repo, you can [check it here](https://github.com/deepjyoti30/downloader-cli/blob/master/.github/workflows/test.yml).

This post was originally published at my [personal blog](https://blog.deepjyoti30.dev)