skip to Main Content

I have an app that does CRUD basically. I am able to run my unit tests locally but on the CI(GitHub Action) it’s failing. I am getting the error because of PostgreSQL. Here you can see the error. I couldn’t be able to fix that. You can access the whole repository on this LINK. You can see my ci.yaml file below;

name: CI

on:
  pull_request:
  push:
    branches: [develop, main]

concurrency:
  group: ci-${{ github.ref }}-group
  cancel-in-progress: true

jobs:
  default:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      - name: Build with Maven
        run: mvn -B package --file pom.xml
      - name: Update dependency graph
        uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
      - name: Build Jar file
        run: ./project-dev build-jar
      - name: Save Jar file
        uses: actions/upload-artifact@v3
        with:
          name: demo-0.0.1-SNAPSHOT
          path: target/demo-0.0.1-SNAPSHOT.jar
          retention-days: 1

Can someone help me to run my unit tests on the CI, please?

2

Answers


  1. You need to make sure that the database runs.

    Your program expects a Posgres DB named school_management to be available under localhost:5432.

    However, such a database isn’t available in your script.

    For setting up the database, you could use the an existing action like this one :

    steps:
    - uses: harmon758/postgresql-action@v1
      with:
        postgresql version: '11'
        postgresql db: school_management
        postgresql user: learning
        postgresql password: sa123456
    

    Alternatively, you could use PosgreSQL service containers as described here:

        # Service containers to run with `container-job`
        services:
          # Label used to access the service container
          postgres:
            # Docker Hub image
            image: postgres
            # Provide the password for postgres
            env:
              POSTGRES_PASSWORD: sa123456
              POSTGRES_USER: learning
              POSTGRES_DB: school_management
            # Set health checks to wait until postgres has started
            options: >-
              --health-cmd pg_isready
              --health-interval 10s
              --health-timeout 5s
              --health-retries 5
    

    However this makes it run using a different hostname so you have to change your spring.datasource.url to jdbc:postgresql://localhost:5432/school_management or similar.

    Integrated in your workflow, it could look like the following:

    name: CI
    
    on:
      pull_request:
      push:
        branches: [develop, main]
    
    concurrency:
      group: ci-${{ github.ref }}-group
      cancel-in-progress: true
    
    jobs:
      default:
        runs-on: ubuntu-latest
            # Service containers to run with `container-job`
        services:
          # Label used to access the service container
          postgres:
            # Docker Hub image
            image: postgres
            # Provide the password for postgres
            env:
              POSTGRES_PASSWORD: sa123456
              POSTGRES_USER: learning
              POSTGRES_DB: school_management
            # Set health checks to wait until postgres has started
            options: >-
              --health-cmd pg_isready
              --health-interval 10s
              --health-timeout 5s
              --health-retries 5
        steps:
          - uses: actions/checkout@v3
          - name: Set up JDK
            uses: actions/setup-java@v3
            with:
              java-version: '17'
              distribution: 'temurin'
          # override spring.datasource.url
          - name: Setup config
            run: |
              mkdir config
              echo 'spring.datasource.url=jdbc:postgresql://postgres:5432/school_management' > config/application.properties
          - name: Build with Maven
            run: mvn -B package --file pom.xml
          - name: Update dependency graph
            uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
          - name: Build Jar file
            run: ./project-dev build-jar
          - name: Save Jar file
            uses: actions/upload-artifact@v3
            with:
              name: demo-0.0.1-SNAPSHOT
              path: target/demo-0.0.1-SNAPSHOT.jar 
              retention-days: 1
    

    Another possibility is to use an embedded database like H2 for tests.

    With this, you don’t have to setup any database.

    Login or Signup to reply.
  2. Looking at your logs line 1351

    org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.

    Your tests are trying to connect to a local Postgres instance that is not available. Also looking at your tests you have both unit and integration tests. Whereas an integration test needs to load the application context meaning that your running application inside of the pipeline will not be able to connect to Postgres. Hence, all of your integration tests will fail that utilize Postgres.

    However, your other tests are passing, line 2085:

    2023-02-14 12:13:39.378 INFO 1740 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:d00124ab-b172-4fd1-bf29-b4836ae2f938;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'

    these are working since your application is connecting correctly to the h2 database that you have.

    the StudentRepositoryTest are working since you have the following annotation in your class @DataJpaTest which will boot up this integration test and connect to the in-memory database.

    I think the test that is failing is the following DemoApplicationTests:

    @SpringBootTest
    class DemoApplicationTests {
    
        @Test
        void contextLoads() {
        }
    
    }
    

    Since this test load the application context (the whole application) and will automatically try to connect with postgres.

    So to fix the issue just delete the file. or a better solution which I would recommend (which is a bit more advanced) is to use something called testcontainers and actually run a postgres database inside of a container.

    The reason why am suggesting the latter solution is normally once you want to run an integration test you try to have the exact solution that your application runs on production. Hence, an h2 database might have edge cases that does not match postgres database

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search