Test, build and release a Shopware 6 Plugin with GitLab CI - Part 3 - test

Insider Blog

When it comes to testing a Shopware 6 plugin, there are two types of test that can be performed:

  1. Testing the code itself (more in the official documentation)
    1. PHP unit test
    2. Jest unit tests in Shopware's storefront
    3. Jest unit tests in Shopware's administration
    4. End-to-End (E2E) Testing
  2. Ensuring high code quality (more in the official documentation)

Code quality

Let's start with code quality because it's easier to run it outside a CI/CD environment.

We will again use the shopware-cli.

shopware-cli extension validate --full --reporter summary .

This will run all the tests described here and hopefully produce an output like this:

✖ 0 problems (0 errors, 0 warnings)

If there are any errors, refer to the Shopware documentation how to fix them and rerun only the failed tests like described here.

Code quality pipeline

Now we will run it in GitLab.

<plugin-root>/.gitlab-ci.yml
stages:
  - test

code-quality:
   image:
      name: ghcr.io/shopware/shopware-cli:latest-php-8.2
      entrypoint: [""]
   stage: test
   script:
      - shopware-cli extension validate --full . | tee report.json
   artifacts:
      reports:
         codequality: report.json
   rules:
      - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
        when: never
      - if: $CI_COMMIT_BRANCH

This pipeline will run on the default branch and on merge request pipelines.

Running on the default branch before build and release prevents from accidentally creating a low-quality release.

A nice touch to the MR pipeline is the Code Quality report integration!

PHP unit test

First of all, we need to configure PHPUnit by following the official shopware documentation

We won't focus here on this process. When everything is setup, we should be able to run our test like this in out Shopware project root:

./vendor/bin/phpunit --configuration="custom/static-plugins/SwagBasicExample"

PHPUnit pipeline

Running PHPUnit for a plugin requires a full Shopware instance. Fortunately, shopware-cli can help us to deal with it.

<plugin-root>/.gitlab-ci.yml
stages:
   - test

phpunit:
  stage: test
  image:
    name: ghcr.io/shopware/shopware-cli:latest-php-8.2
    entrypoint: [""]
  services:
    - name: mysql:8.3.0
      alias: test_database
      variables:
        MYSQL_SKIP_TEST_DB: 'yes'
        MYSQL_ALLOW_EMPTY_PASSWORD: yes
  variables:
    GIT_STRATEGY: none
    SHOPWARE_ROOT: ${CI_PROJECT_DIR}/shopware
    SHOPWARE_VERSION: 6.6.10.13
    
    APP_SECRET: def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48
    MESSENGER_TRANSPORT_DSN: sync://
    DATABASE_URL: mysql://root@test_database/shopware
    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer

    XDEBUG_MODE: coverage
  before_script:
    - apk add --no-cache php-8.2-xdebug
    - shopware-cli project create shopware ${SHOPWARE_VERSION}
    - cd $SHOPWARE_ROOT
    - composer req --dev shopware/dev-tools phpunit/phpunit
    - git clone "https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "custom/plugins/${CI_PROJECT_NAME}"
    - cd custom/plugins/${CI_PROJECT_NAME}
    - git checkout ${CI_COMMIT_SHA}
    - cd ${SHOPWARE_ROOT}
    - composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)
    - cd custom/plugins/${CI_PROJECT_NAME}
  script:
    - ${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml

  cache:
    - key: $CI_JOB_NAME
      paths:
        - $COMPOSER_CACHE_DIR
  coverage: /^\s*Lines:\s*\d+.\d+\%/
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.cobertura.xml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: never
    - if: $CI_COMMIT_BRANCH

Let's explain this a little

  1. We disable automatic repository cloning (16)
  2. We include a database service (9-14)
  3. We set some required Shopware env variables (20-23)
  4. Create an empty shopware project with phpunit and xdebug (27-36)
  5. Run PHPUnit with code coverage generation as text and in cobertura format (38)

Like the Code quality pipeline, this takes full advantage of GitLab coverage reporting

Putting it all together

For this part, we don't include the build and release part.

<plugin-root>/.gitlab-ci.yml
stages:
   - test

phpunit:
  stage: test
  image:
    name: ghcr.io/shopware/shopware-cli:latest-php-8.2
    entrypoint: [""]
  services:
    - name: mysql:8.3.0
      alias: test_database
      variables:
        MYSQL_SKIP_TEST_DB: 'yes'
        MYSQL_ALLOW_EMPTY_PASSWORD: yes
  variables:
    GIT_STRATEGY: none
    SHOPWARE_ROOT: ${CI_PROJECT_DIR}/shopware
    SHOPWARE_VERSION: 6.6.10.13
    
    APP_SECRET: def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48
    MESSENGER_TRANSPORT_DSN: sync://
    DATABASE_URL: mysql://root@test_database/shopware
    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer

    XDEBUG_MODE: coverage
  before_script:
    - apk add --no-cache php-8.2-xdebug
    - shopware-cli project create shopware ${SHOPWARE_VERSION}
    - cd $SHOPWARE_ROOT
    - composer req --dev shopware/dev-tools phpunit/phpunit
    - git clone "https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "custom/plugins/${CI_PROJECT_NAME}"
    - cd custom/plugins/${CI_PROJECT_NAME}
    - git checkout ${CI_COMMIT_SHA}
    - cd ${SHOPWARE_ROOT}
    - composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)
    - cd custom/plugins/${CI_PROJECT_NAME}
  script:
    - ${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml

  cache:
    - key: $CI_JOB_NAME
      paths:
        - $COMPOSER_CACHE_DIR
  coverage: /^\s*Lines:\s*\d+.\d+\%/
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.cobertura.xml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: never
    - if: $CI_COMMIT_BRANCH

code-quality:
   image:
      name: ghcr.io/shopware/shopware-cli:latest-php-8.2
      entrypoint: [""]
   stage: test
   script:
      - shopware-cli extension validate --full . | tee report.json
   artifacts:
      reports:
         codequality: report.json
   rules:
      - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
        when: never
      - if: $CI_COMMIT_BRANCH

Author

Robert Juzak , B.Sc.

Characteristics

released:

March 26, 2026

categories:

What moves us, DevOps

Tags:

DevOps, Open Source, Shopware
previous article