Testing And Benchmarking in Fortran

Here’s the translation of the Go testing and benchmarking example to Fortran, formatted in Markdown suitable for Hugo:

! Unit testing is an important part of writing principled Fortran programs.
! While Fortran doesn't have a built-in testing framework like Go's testing package,
! we can create a simple testing framework ourselves.

! For the sake of demonstration, this code is in the main program,
! but it could be in any module. Testing code typically lives in the same
! module as the code it tests.

program testing_and_benchmarking
    implicit none
    
    ! We'll be testing this simple implementation of an integer minimum.
    ! Typically, the code we're testing would be in a separate module.
    
    contains
    
    integer function IntMin(a, b)
        integer, intent(in) :: a, b
        if (a < b) then
            IntMin = a
        else
            IntMin = b
        end if
    end function IntMin
    
    ! A test is created by writing a subroutine with a descriptive name.
    
    subroutine TestIntMinBasic()
        integer :: ans
        ans = IntMin(2, -2)
        if (ans /= -2) then
            print *, "Error: IntMin(2, -2) = ", ans, "; want -2"
        end if
    end subroutine TestIntMinBasic
    
    ! Writing tests can be repetitive, so it's useful to use a table-driven style,
    ! where test inputs and expected outputs are listed in an array and a single loop
    ! walks over them and performs the test logic.
    
    subroutine TestIntMinTableDriven()
        integer, parameter :: num_tests = 5
        integer :: tests(num_tests, 3) = reshape([ &
            0,  1,  0, &
            1,  0,  0, &
            2, -2, -2, &
            0, -1, -1, &
           -1,  0, -1  &
        ], [num_tests, 3])
        integer :: i, ans
        
        do i = 1, num_tests
            ans = IntMin(tests(i, 1), tests(i, 2))
            if (ans /= tests(i, 3)) then
                print *, "Error: IntMin(", tests(i, 1), ",", tests(i, 2), &
                         ") = ", ans, "; want ", tests(i, 3)
            end if
        end do
    end subroutine TestIntMinTableDriven
    
    ! Benchmark tests in Fortran typically involve timing the execution
    ! of a function over many iterations.
    
    subroutine BenchmarkIntMin()
        integer, parameter :: num_iterations = 1000000
        integer :: i
        real :: start_time, end_time
        
        call cpu_time(start_time)
        do i = 1, num_iterations
            call IntMin(1, 2)
        end do
        call cpu_time(end_time)
        
        print *, "BenchmarkIntMin: ", num_iterations, " iterations in ", &
                 end_time - start_time, " seconds"
    end subroutine BenchmarkIntMin
    
    ! Main program to run all tests and benchmarks
    
    call TestIntMinBasic()
    call TestIntMinTableDriven()
    call BenchmarkIntMin()
    
end program testing_and_benchmarking

To run the program:

$ gfortran -o testing_and_benchmarking testing_and_benchmarking.f90
$ ./testing_and_benchmarking
BenchmarkIntMin:     1000000  iterations in    0.00300000014 seconds

This Fortran code demonstrates a basic approach to testing and benchmarking. Unlike Go, Fortran doesn’t have built-in testing or benchmarking frameworks, so we’ve implemented simple versions ourselves. The structure and explanations have been adapted to fit Fortran’s syntax and conventions.

In this example:

  1. We define the IntMin function that we want to test.
  2. We create test subroutines (TestIntMinBasic and TestIntMinTableDriven) that check the function’s correctness.
  3. We implement a simple benchmarking subroutine (BenchmarkIntMin) that measures the time taken to run the function many times.
  4. In the main program, we call all our test and benchmark subroutines.

Note that this is a basic implementation. For more comprehensive testing in Fortran, you might want to use a testing framework like pFUnit or FRUIT, which provide more features and better integration with build systems.