Instructor Notes

This is a placeholder file. Please add content here.

What is a Unit Test


Instructor Note

Challenge 2 should be lead by the instructor and done as a class activity. Part 3 can be skipped if there is limited time.



Writing your first unit test


pFUnit basics


Instructor Note

The dot function should only be a wrapper around the intrinsic function dot_product to keep the example simple but incorporate compiling src and tests together:

FORTRAN

module matrix_ops
    implicit none
contains
    !> Returns the dot product (a.b) of the two inputted arrays a and b
    integer function dot(a, b)
        !> The two arrays to be dotted together
        integer :: a(:), b(:)

        dot = dot_product(a, b)
    end function dot
end module matrix_ops

When writing the pFUnit version of the unit test for the dot product, begin from this standard Fortran version to highlight the benefits of pFUnit.

FORTRAN

program test_matrix_ops_dot
    use matrix_ops, only : dot
    implicit none

    integer :: i

    ! Declare passed and failure message arrays to be set by a test subroutine(s)
    logical :: passed(1)
    character(len=200) :: failure_message(1)

    ! Define set of tests for dot
    call test_dot_one_to_twenty(passed(1), failure_message(1))

    if (all(passed)) then
        write(*,*) "All tests passed!"
    else
      do i = 1, size(passed)
          if (.not. passed(i)) then
              write(*,*) "FAIL: ", trim(failure_message(i))
          end if
      end do
      stop 1
    end if

contains
    !> Unit test subroutine for dot
    subroutine test_dot_one_to_twenty(passed, failure_message)
        !> A logical to track whether the test passed or not
        logical, intent(out) :: passed
        !> A failure message to be displayed if passed is false
        character(len=200), intent(out) :: failure_message

        integer :: a(10), b(10), expected_c, actual_c

        ! Define inputs and expected outputs for the scenario we want to test
        a = [1,2,3,4,5,6,7,8,9,10]
        b = [11,12,13,14,15,16,17,18,19,20]
        expected_c = 935

        actual_c = dot(a, b)

        ! Check that the actual value matches the expected value
        passed = expected_c == actual_c

        ! Populate the failure message
        write(failure_message, '(A,I3,A,I3)') "Expected ", expected_c, " but got ", actual_c

    end subroutine test_dot_one_to_twenty
end program test_matrix_ops_dot

This should be able to be compiled with the command gfortran matrix_ops.f90 test_dot.f90



Instructor Note

To build and run this pFUnit version. Use the CMakeLists.txt below:

CMAKE

cmake_minimum_required(VERSION 3.9 FATAL_ERROR)

# Set project name
project(
  "matrix_ops"
  LANGUAGES "Fortran"
  VERSION "0.0.1"
  DESCRIPTION "Library for matrix operations"
)

# Define a variable which stores a list of src files
set(SRC_DIR "${PROJECT_SOURCE_DIR}")
set(PROJ_SRC_FILES "${SRC_DIR}/matrix_ops.f90")

#---------------------------
# Configure testing.
#---------------------------
enable_testing()

find_package(PFUNIT REQUIRED)

# Create library for src code
add_library(SUT STATIC ${PROJ_SRC_FILES})

# List all test files
set(test_srcs "${PROJECT_SOURCE_DIR}/test_dot.pf")

# Add the test target
add_pfunit_ctest (test_dot
  TEST_SOURCES ${test_srcs}
  LINK_LIBRARIES SUT # your application library
  )

This can then be compiled with the following commands:

SH

cmake -B build -DCMAKE_PREFIX_PATH="/path/to/pfunit/build/installed"
cmake --build build
./build/test_dot


Integrating with build systems


Parameterising pFUnit tests


Instructor Note

The following challenge will take learners a long time to complete. Therefore, for shorter workshops, it is recommended to skip this and/or suggest it as some homework.



Testing parallel code


Instructor Note

When writing out the new MPI versions of the dot_product test, it is best to start from the serial version to emphasize the similarities between the two.



Appendix