unit-testingfortranfortran2008

How to unit test functions whose interfaces are defined within submodules


It seems to me that one of the nice features of submodules is that you can create a helper function in a submodule at very little cost to the programmer; you don't trigger a compilation cascade, you don't clutter the namespace or your documentation, and it is immediately clear where that function can and can't be used. They're like nicer versions of private functions.

However, functions in submodules cannot be used. While this is working as intended, it also appears that this prevents the function from being unit tested. Both unit test frameworks that I'm aware of, pFUnit and fruit, require use syntax to operate.

There are some (imho somewhat inelegant) workarounds for the same problem with private functions discussed in How to access private variables in fortran modules?, but none of those solutions appear to work for functions in submodules, at least not without negating all of the benefits of putting those functions in submodules in the first place.

So are there any solutions to this problem?


Solution

  • I have little experience with submodules (so not sure if this is useful), but just to extend my comment above...

    !! parent_mod.f90 (public things)
    module parent_mod
        implicit none
    
        type myint_t
            integer :: n = 100
        contains
            procedure :: add, show
        endtype
    
        interface
            module subroutine add( x )
                class(myint_t) :: x
            end
            module subroutine show( x )
                class(myint_t) :: x
            end
        endinterface
    end
    
    !! parent_helper.f90 (private things to be used by parent_impl.f90
    !! and possibly by unit tests)
    module parent_helper
        use parent_mod, only: myint_t
        implicit none
    contains
        subroutine debug_show( x )
            type(myint_t) :: x
            print *, "debug: x = ", x
        end
    end
    
    !! parent_impl.f90  (implementation)
    submodule (parent_mod) parent_impl
        implicit none
    contains
        module procedure add
            x% n = x% n + 1
        end
        module procedure show
            use parent_helper, only: debug_show
            call debug_show( x )
        end
    end
    
    !! main.f90
    program main
        use parent_mod, only: myint_t
        implicit none
        type(myint_t) :: a
    
        call a% add()
        call a% show()  !! 101
    
        call a% add()
        call a% show()  !! 102
    
        block
          use parent_helper
          call debug_show( a )  !! 102
        endblock
    end
    
    !! build
    $ gfortran-10 -fcheck=all -Wall -Wextra parent_mod.f90 parent_helper.f90 parent_impl.f90 main.f90
    

    Does this possibly help avoid recompilation of parent_mod.f90 (even when parent_helper or parent_impl are modified)? (And I noticed that the module name "parent" has no meaning here... XD)