9. JUnit integration

Molecule supports test reporting through a regular Ansible ansible.builtin.junit callback. Configure the callback in the provisioner section of molecule.yml by setting environment variables. Having this, each task prefixed with TEST_CASE will be reported to the junit report file located in the reports directory relative to the test home.

# molecule.yml (fragment)
provisioner:
  name: ansible
  playbooks:
    converge: ../../apache1_debian.yml

  env:
    ANSIBLE_CALLBACKS_ENABLED: ansible.builtin.junit
    JUNIT_TEST_CASE_PREFIX: "TEST_CASE"
    JUNIT_OUTPUT_DIR: "reports"

The verify.yml file looks as before, with the only change: TEST_CASE prefixes for assertion tasks.

# verify.yml
---
- name: Verify
  hosts: webservers
  become: true
  tasks:
    - name: Check if Apache is installed
      ansible.builtin.package_facts:
        manager: auto

    - name: "TEST_CASE: Verify Apache package is installed"
      ansible.builtin.assert:
        that:
          - "'apache2' in ansible_facts.packages"
        fail_msg: "Apache (apache2) package is not installed"

    # === Service Block ===
    - name: Gather service facts
      ansible.builtin.service_facts:

    - name: "TEST_CASE: Assert apache2 service is running on Debian"
      ansible.builtin.assert:
        that:
          - "'apache2' in ansible_facts.services"
          - "ansible_facts.services['apache2'].state == 'running'"
        fail_msg: "Apache (apache2) service is not running on Debian system"
        success_msg: "Apache (apache2) service is running on Debian system"

    # === TCP Block ===
    - name: "TEST_CASE: Check if port 80 is open (Apache)"
      ansible.builtin.wait_for:
        port: 80
        host: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}"
        state: started
        timeout: 5
      register: apache_port_check

    - name: "TEST_CASE: Assert port 80 is accessible"
      ansible.builtin.assert:
        that:
          - apache_port_check.state == "started"
        fail_msg: "Port 80 is not accessible"
        success_msg: "Port 80 is accessible"

During execution of such test, the junit report file is being populated with data in the report directory.

molecule test -s junit

After the test, the report must be converted from native xml format using any regular junit tool. Instead of looking for an available tool, I asked ChatGPT to create a simple script that converts the report to a dynamic HTML report.

A converter script is available in the bin directory generating a dynamic HTML report. Below code processes the latest report from junit scenario.

verify_junit=$(ls -t molecule/junit/reports/verify*.xml | head -n 1)
bin/convert_junit_report.sh $verify_junit

Exemplary test report is available here: JUnit HTML Report