Test a FastAPI project
FastAPI is a modern and highly performant web framework that you can use to build APIs in Python 3.7+ using standard Python type hints. In this tutorial, you'll use Harness CI to automatically run tests on your FastAPI project when changes are pushed to a specific branch of your code repository.
Prerequisites
You need the following for this tutorial:
- Knowledge of Python, FastAPI, Git, and GitHub.
- A GitHub account.
- A Harness account.
If you don't have a Harness account yet, you can create one for free at app.harness.io.
Prepare the codebase
- Fork the fastapi-harness-sample repository into your GitHub account.
- In Harness, create a project or select an existing project, and then go to the CI module.
- Select Connectors under Project Setup.
- Select New Connector, and select GitHub under Code Repositories.
- Configure the GitHub connector settings so that the connector can access your fork of the sample repo.
The sample repo has a simple FastAPI project and unit tests. Notable files include:
fastapi-todo-tests/requirements.txt
: Contains a list of project dependencies.fastapi-todo-tests/app/main.py
: The sample FastAPI project builds a "To Do" list. It has three API endpoints, one that creates tasks, one that deletes tasks, and one that gets the task list.fastapi-todo-tests/test_main.py
: Defines three test cases.
Optional exercise: Local set up
Optionally, you can build the project and test it locally before running tests in a Harness CI pipeline.
Make sure you have Python/Python3 and Uvicorn installed on your local machine.
Clone the FastAPI sample repo to your local machine.
The sample repo should have the following structure:
├── .harness
│ ├── Pipeline.yaml
├── app
│ ├── main.py
│ ├── schemas.py
│ ├── util.py
│ ├── __init__.py
├── LICENSE
├── README.md
├── requirements.txt
└── test_main.pyCreate a virtual environment named
test-env
.- Linux or macOS:
python3 -m venv test-env
- Windows:
python -m venv test-env
- Linux or macOS:
Activate the virtual environment.
- Linux or macOS:
source test-env/bin/activate
- Windows:
.\test-env\Scripts\activate
- Linux or macOS:
Install dependencies.
cd <project root>
pip install -r requirements.txtRun tests defined in
test_main.py
.pytest
Start the development server.
uvicorn app.main:app --reload
Navigate to
localhost:8000/docs
on your browser to access the local server test environment.
Prepare the pipeline
These steps summarize pipeline creation. For more information, go to CI pipeline creation overview.
- In your Harness project, go to the CI module.
- Select Pipelines, and then select Create a Pipeline.
- Enter a Name and select Start.
- Add a Build (
CI
) stage.
Add the Build stage and infrastructure
- Visual
- YAML
- Select Add Stage, and select the Build stage.
- Enter a Stage Name, such as
Test FastAPI
. - For Connector, select the GitHub connector you created earlier in Prepare the codebase.
- Select Set Up Stage.
- In the Build stage, select the Infrastructure tab, and set up your build infrastructure.
In the Pipeline Studio's YAML editor, add a CI
stage and set up your build infrastructure.
For example, this CI stage uses Harness Cloud build infrastructure:
- stage:
name: test
identifier: test
type: CI
spec:
cloneCodebase: true
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
...
And this CI stage uses a Kubernetes cluster build infrastructure:
- stage:
name: test
identifier: test
type: CI
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR_ID
namespace: YOUR_KUBERNETES_NAMESPACE
automountServiceAccountToken: true
nodeSelector: {}
os: Linux
execution:
steps:
...
Install dependencies
Add a Run step to install dependencies for the FastAPI project.
- Harness Cloud
- Self-hosted
- step:
type: Run
name: Install Dependencies
identifier: Install_Dependencies
spec:
shell: Sh
command: |-
sudo apt-get update && sudo apt-get install -y python3-dev && sudo apt-get install default-libmysqlclient-dev
pip install --cache-dir .pip_cache -r requirements.txt
envVariables:
PIP_CACHE_DIR: /root/.cache
- step:
type: Run
name: Install Dependencies
identifier: Install_Dependencies
spec:
connectorRef: account.harnessImage
image: python:latest
shell: Sh
command: |-
sudo apt-get update && sudo apt-get install -y python3-dev && sudo apt-get install default-libmysqlclient-dev
pip install --cache-dir .pip_cache -r requirements.txt
Run tests
Add a Run step that runs unit tests and outputs the results in JUnit XML format.
This tutorial runs basic unit tests, but you can run all types of tests (integration tests, mutation tests, and so on) in Harness CI. For more information, go to Run tests in CI pipelines.
- Harness Cloud
- Self-hosted
- step:
type: Run
name: Pytest
identifier: Pytest
spec:
shell: Sh
command: |-
pytest test_main.py --junit-xml=output-test.xml
reports:
type: JUnit
spec:
paths:
- output-test.xml
- step:
type: Run
name: Pytest
identifier: Pytest
spec:
connectorRef: account.harnessImage
image: python:latest
shell: Sh
command: |-
pytest test_main.py --junit-xml=output-test.xml
reports:
type: JUnit
spec:
paths:
- output-test.xml
To view test reports in Harness, test results must be in JUnit XML format, and the reports
specification must be included.
Add the trigger
You can run this pipeline manually as it is, or you can add a trigger to automatically run these tests whenever the codebase changes. To do this, add a Git event trigger that listens for an event on a specific branch of your FastAPI repo fork.
For this tutorial, you'll create a trigger that listens for pushes to the main
branch.
- In Harness, in the same pipeline, select Triggers in the Pipeline Studio header, and then select Add New Trigger.
- Select GitHub under Webhook.
- Enter a Name.
- For Connector, select your GitHub connector, and enter the FastAPI repo name if necessary.
- For Event, select Push.
- Select Continue
- On the Conditions tab, configure a Branch Name condition. Set the Operator to Equals, and set the Matches Value to
main
. The entire condition should read likeBranch Name = main
. - Select Continue, and select Create Trigger.
GitHub webhooks are usually automatically created in the target repo. If automatic registration fails, you must manually copy the webhook URL and add it to your repo webhooks. For instructions on manual webhook registration, go to Register the webhook in the Git provider.
Run the pipeline
To test the Git event trigger and run the pipeline, go to your FastAPI repo fork, make a change, and commit and push it to main
. For this tutorial, you could commit directly to main
, but in a real world development situation, you would want to create and merge a PR.
Upon pushing to main
(either directly or by merging a PR), the trigger should start your pipeline within a few moments. While the build runs, you can view the logs and monitor build activity on the Build details page.
After the pytest step runs, you can find logs indicating that the output-test.xml
file was generated, and you can view the test results on the Tests tab.
Complete YAML examples
Here are complete YAML examples for this tutorial. If you copy these examples, make sure to replace the placeholders with valid values.
Pipeline YAML
These pipelines include a Build (CI
) stage with two Run steps. One step installs dependencies defined in requirements.txt
and the other runs unit tests.
- Harness Cloud
- Self-hosted
This example uses Harness Cloud build infrastructure.
pipeline:
name: YOUR_PIPELINE_NAME
identifier: YOUR_PIPELINE_ID
projectIdentifier: YOUR_HARNESS_PROJECT_ID
orgIdentifier: default
tags: {}
properties:
ci:
codebase:
connectorRef: YOUR_GITHUB_CONNECTOR_ID
repoName: fastapi-harness-sample
build: <+input>
stages:
- stage:
name: test
identifier: test
type: CI
spec:
cloneCodebase: true
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: Install Dependencies
identifier: Install_Dependencies
spec:
shell: Sh
command: |-
sudo apt-get update && sudo apt-get install -y python3-dev && sudo apt-get install default-libmysqlclient-dev
pip install --cache-dir .pip_cache -r requirements.txt
envVariables:
PIP_CACHE_DIR: /root/.cache
- step:
type: Run
name: Pytest
identifier: Pytest
spec:
shell: Sh
command: |
pytest test_main.py --junit-xml=output-test.xml
reports:
type: JUnit
spec:
paths:
- output-test.xml
This example uses a Kubernetes cluster build infrastructure.
pipeline:
name: YOUR_PIPELINE_NAME
identifier: YOUR_PIPELINE_ID
projectIdentifier: YOUR_HARNESS_PROJECT_ID
orgIdentifier: default
tags: {}
properties:
ci:
codebase:
connectorRef: YOUR_GITHUB_CONNECTOR_ID
repoName: fastapi-harness-sample
build: <+input>
stages:
- stage:
name: test
identifier: test
type: CI
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR_ID
namespace: YOUR_KUBERNETES_NAMESPACE
automountServiceAccountToken: true
nodeSelector: {}
os: Linux
execution:
steps:
- step:
type: Run
name: Install Dependencies
identifier: Install_Dependencies
spec:
connectorRef: account.harnessImage
image: python:latest
shell: Sh
command: |-
sudo apt-get update && sudo apt-get install -y python3-dev && sudo apt-get install default-libmysqlclient-dev
pip install --cache-dir .pip_cache -r requirements.txt
- step:
type: Run
name: Pytest
identifier: Pytest
spec:
connectorRef: account.harnessImage
image: python:latest
shell: Sh
command: |
pytest test_main.py --junit-xml=output-test.xml
reports:
type: JUnit
spec:
paths:
- output-test.xml
Trigger YAML
Trigger YAML is separate from pipeline YAML. However, you can write triggers in a YAML editor just as you can for pipelines. The YAML for this tutorial's trigger is as follows:
trigger:
name: fastapi trigger
identifier: fastapi_trigger
enabled: true
encryptedWebhookSecretIdentifier: ""
description: ""
tags: {}
orgIdentifier: default
stagesToExecute: []
projectIdentifier: YOUR_HARNESS_PROJECT_ID
pipelineIdentifier: YOUR_PIPELINE_ID
source:
type: Webhook
spec:
type: Github
spec:
type: Push
spec:
connectorRef: YOUR_GITHUB_CONNECTOR_ID
autoAbortPreviousExecutions: false
payloadConditions:
- key: targetBranch
operator: Equals
value: main
headerConditions: []
repoName: fastapi-harness-sample
actions: []