Unit Testing with PlatformIO: Part 3. Continuous Integration and Remote Testing

Integration with GitHub Actions and introduction to PlatformIO Remote

Valerii Koval
Valerii Koval
Head of System Integration at PlatformIO Labs
Share:

In recent years Continuous Integration (CI) has become a standard for software development and embedded projects are no exception. Continuous integration allows developers to build an application and run tests in an automated way. Whenever new changes are committed to the repository, the CI system executes predefined tasks to make sure that the project works as expected and no regression was introduced. Besides compiling and running tests, we also can perform additional actions like static code analysis, applying code formatting, etc.

In the previous posts (Part 1, Part 2) we’ve covered the basics of unit testing and put together a practical development environment for writing and running tests on both sides: the host machine and an embedded device. This article will show how to set up a simple CI workflow based on the GitHub Actions service and then configure the CI server to run the tests on a remote device using PlatformIO Remote Development Solution.

Prerequisites

Besides the prerequisites from the previous posts, today we will also need:

  • PlatformIO account
  • GitHub account

Setting Up GitHub Actions

GitHub Actions is an automation feature that allows you to automate, customize, and execute software development workflows right in your GitHub repository. Registering on GitHub, creating a new repository, and pushing the code are out of the scope of this article. If you’re new to GitHub, check out the official Getting Started guide from the GitHub team. Let’s suppose we already have a working repository with the code and tests from the previous posts.

We will start straight from defining our workflows in a GitHub Actions configuration file. First, let’s create a new file .github/workflow/native.yml with the following contents:

on: [push, pull_request]

jobs:
  test:

    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]

    steps:
    - uses: actions/checkout@v1
    - name: Set up Python
      uses: actions/setup-python@v1
    - name: Install PlatformIO
      run: |
        python -m pip install --upgrade pip
        pip install platformio
    - name: Run tests on the native platform
      run: platformio test -e native

The contents of the configuration file is pretty straightforward. First, we specify GitHub events that trigger the workflow, then we create a matrix to run the workflow on three popular operating systems. The most interesting part is steps section that describes each step required to run our workflow. If we push this file to the repository we will see that all our tests passed successfully:

Running Tests on a Remote Target

PlatformIO offers a unique tool called PlatformIO Remote that allows users to run tests on a remote machine or remote target device without extra software, SSH, VPN or opening network ports. First of all, to enable this feature we need to generate a special token on the machine which the target board is connected to. It can be done in the Account Page or via the platformio account token CLI command:

After that, the token must be added to the Secrets page in the settings of the repository:

After that, we can add a new step to the workflow that runs the tests on the remote board:

on: [push, pull_request]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Set up Python
      uses: actions/setup-python@v1
    - name: Install PlatformIO
      run: |
        python -m pip install --upgrade pip
        pip install platformio
    - name: Run tests on the embedded target
      env:
        PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
      run: platformio remote test -e hifive1-revb -v

The configuration slightly differs from the previous one. This time, we use one OS instead of a matrix with OSes and invoke the remote counterpart for test command.

Before committing the latest changes, we need to start PlatformIO Remote agent that handled all the heavy lifting starting from establishing a secure connection up to collecting test results and sending them to the CI service. Just type platformio remote agent start on the remote machine and we are ready to go.

Finally, we are ready to push the updated configuration file. When the CI system detects a new commit it will automatically run the tests on the remote board:

Summary

Adopting CI practices in embedded projects might be sophisticated, but it’s definitely worth the effort. Leveraging modern CI services helps ensure that code coming from other developers doesn’t break the project. Another benefit of CI is that it greatly reduces the chances of failures by detecting errors early in the development process. Using the PlatformIO Remote feature considerably simplifies the process of executing tests on a remote target. With only a few commands we can run tests and safely transfer results directly to the CI service while real hardware is physically connected to a local machine.

Final Words

Writing good and comprehensive tests is a complex task, and we’ve barely scratched the surface. The overall goal of this three-part series was to create a convenient and automated development environment that allows developers to concentrate on writing code instead of wrestling with boring, complicated tools and configurations.

Stay in touch with us

We hope you found this series useful and that you can now appreciate the power of unit testing. Please follow us on LinkedIn to keep up to date with all our activity.

Valerii Koval
Valerii Koval
Share:

Have questions?

Join the discussion on our forum