Tutorial - 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.
In addition to a Harness account, this tutorial requires a GitHub account and knowledge of Python, FastAPI, Git, and GitHub.
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. The sample repo has a basic 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.
 
- 
In Harness, create a project or select an existing project, and then select the CI module. 
- 
Create a GitHub connector that can access your fork of the sample repo. GitHub connectors can connect to one repo or all repos in an account. 
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.py
- 
Create 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.txt
- 
Run tests defined in test_main.py.pytest
- 
Start the development server. uvicorn app.main:app --reload
- 
Navigate to localhost:8000/docson your browser to access the local server test environment.
Prepare the pipeline
- Create a Harness CI pipeline.
- Add a Build stage, and select the GitHub connector you created in Prepare the codebase.
- You can use any build infrastructure. To follow along with this tutorial,use either Harness Cloud build infrastructure or a Kubernetes cluster build infrastructure.
Install dependencies
Add a Run step to install dependencies for the FastAPI project.
- Harness Cloud
- Kubernetes cluster
- 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: YOUR_IMAGE_REGISTRY_CONNECTOR
      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 (such as integration tests, mutation tests, and so on) in Harness CI. For more information, go to Run tests in CI pipelines.
- Harness Cloud
- Kubernetes cluster
- 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: YOUR_IMAGE_REGISTRY_CONNECTOR
      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 in the step settings.
Pipeline YAML examples
Here are YAML examples of the pipeline created in this tutorial. One example uses Harness Cloud build infrastructure and the other uses a Kubernetes cluster build infrastructure. for this tutorial.
These pipelines include a Build stage with two Run steps. One step installs dependencies defined in requirements.txt and the other runs unit tests.
Pipeline with Harness Cloud build infrastructure
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
Pipeline with Kubernetes cluster build infrastructure
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: YOUR_IMAGE_REGISTRY_CONNECTOR
                    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: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: python:latest
                    shell: Sh
                    command: |
                      pytest test_main.py --junit-xml=output-test.xml
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - output-test.xml
Add the trigger
You can run this pipeline manually, 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.
Test the trigger
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.
Trigger YAML example
You can write triggers in a YAML editor, just as you can for pipelines. However, trigger YAML is stored separately from pipeline YAML. Here's a YAML example of this tutorial's trigger:
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: []