FOSDEM 2026: Testing and Continuous Delivery devroom
University College London
2026-01-31
| Repository | Description | Integration tests | Unit tests |
|---|---|---|---|
| epochpic/epoch |
Popular particle-in-cell plasma code | ||
| ukaea/ReMKiT1D |
Framework for 1D multifluid and kinetic simulations of Tokamaks | ||
| geoschem/geos-chem |
Popular atmospheric chemistry code | ||
| MetOffice/ukca |
The UK’s main atmospheric chemistry code | ||
| MetOffice/lfric_core |
The Met Office’s next generation weather model |
Note that these points are from my experience in academia.
A list of known Fortran testing frameworks on the Fortran wiki
A list of Fortran libraries and tools on the fortran-lang website.
The framework I tend to choose to work with is pFUnit, because…
.pf files to .f90..pf syntax is similar to .f90 with preprocessor directives, such as @Test and @assertEqual.
module test_something
use maths_operations, only : double_int
use funit
implicit none
contains
@Test
subroutine test_double_int_1()
integer :: input, actual_output
input = 1
call double_int(input, actual_output)
@assertEqual(2, actual_output, "Unexpected output from double_int")
end subroutine test_double_int_1
end module test_something.pf with directives into .f90.pFUnit can be integrated into both Make and CMake build systems using functions provided by pFUnit
# Include PFUNIT.mk from a locally installed version of pFUnit
PFUNIT_INCLUDE_DIR ?= $(ROOT_DIR)/../pfunit/build/installed/PFUNIT-4.12/include
include $(PFUNIT_INCLUDE_DIR)/PFUNIT.mk
TEST_FLAGS = $(PFUNIT_EXTRA_FFLAGS) -I$(BUILD_DIR) $(FC_FLAGS) $(LIBS)
# Define variables to be picked up by make_pfunit_test
tests_TESTS = \
test_something.pf \
test_something_else.pf
tests_OTHER_SOURCES = $(filter-out $(BUILD_DIR)/main.o, $(SRC_OBJS))
tests_OTHER_LIBRARIES = $(TEST_FLAGS)
# Triggers pre-processing and defines rule for building test executable
$(eval $(call make_pfunit_test,tests))
# Converts pre-processed test files into objects ready for building of the executable
%.o: %.F90
$(FC) -c $(TEST_FLAGS) $<find_package(PFUNIT REQUIRED)
# Filter out the main.f90 files. We can only have one main() function in our tests
set(PROJ_SRC_FILES_EXEC_MAIN ${PROJ_SRC_FILES})
list(FILTER PROJ_SRC_FILES_EXEC_MAIN EXCLUDE REGEX ".*main.f90")
# Create library for src code
add_library (sut STATIC ${PROJ_SRC_FILES_EXEC_MAIN})
# List all test files
set(test_srcs
"${PROJECT_SOURCE_DIR}/tests/test_something.pf"
"${PROJECT_SOURCE_DIR}/tests/test_something_else.pf"
)
# Triggers pre-processing and defines rule for building test executable
add_pfunit_ctest (test_something_interesting
TEST_SOURCES ${test_srcs}
LINK_LIBRARIES sut # your application library
)To ensure a consitent environment when running pFUnit tests through GitHub actions, one can make use of containerisation (Docker, in my case)…
See UCL-ARC/fortran-unit-testing-exercises for an example of this being used in practice
FROM parent-image:main
# Copy src and test code into the container
COPY my-project /my-project
WORKDIR /my-project
# Build tests with cmake
RUN cmake -B build -DCMAKE_PREFIX_PATH=/path/to/pfunit/build/installed && \
cmake --build build
# Run pfunit tests with ctest
RUN ctest --test-dir build --output-on-failureI have been developing a software carpentry style lesson for unit testing in Fortran.
.pf files to .f90.Scan to view the slides

Unit testing in Fortran - Back to talks