3

I know the idea of private variables is that they shouldn't be accessed, and I do want it to work this way when using the module in the rest of the program, but I need it for the purpose of checking the internal workings of the module.

Say I have the following simplified example:

module mod
  implicit none
  private
  integer :: value
  public :: set_value

contains

subroutine set_value(input)
  implicit none
  integer,intent(in) :: input
  value=input
end subroutine

end module

And I now want to test the subroutine to see if it is actually doing what I want: I would like to write a program that uses the module, calls the routine set_value with input 8 and then checks if the internal variable value is now 8.

Can I do this? Or is it there another way to unit test initializers of private variables?

Nordico
  • 1,226
  • 2
  • 15
  • 31
  • 4
    write a `get_value` function and use that to test. – casey Sep 29 '15 at 17:10
  • Even if I would only use that function for the purpose of testing? Also, wouldn't I be testing both routines at once then? – Nordico Sep 29 '15 at 17:29
  • If you do not want to follow @casey, simply set it public for the purpose of testing, and set it back to private after that! – innoSPG Sep 29 '15 at 17:41

1 Answers1

7

You have three approaches as I see them.

  1. write a get function to get the value and test. You indicate in the comments that this is sub-optimal though, so..

  2. If you have a compiler with Fortran 2003 support (e.g. any recent version of a modern Fortran compiler), declare the variable with the protected attribute instead of the private attribute. This will allow your variable to be read from any code, but not modified. This will enforce that it can only be set via your setter function but you can inspect its value directly in your unit test.

    integer, protected :: value
    
  3. Lastly, if all else fails, you can conditionally compile the module so that sometimes the variable is not private. For example, do this:

    module mod
      implicit none
      private
      integer :: value
      public :: set_value
    
    #ifdef UNITTESTING
      public :: value
    #endif
    
    contains
    ...
    end module
    

    Then change the filename from .f90 to .F90 so that it will be pre-processed (at least on gfortran and ifort). When you compile it normally, value will be private, but if you instead compile with the flag -DUNITTESTING then value will be public. When you compile your test cases, you use that flag and they can now inspect the variable directly.

casey
  • 6,855
  • 1
  • 24
  • 37
  • Please, not conditional compilation ... An alternative might be protected, see http://stackoverflow.com/questions/15020460/protected-global-variables-in-fortran – Ian Bush Sep 29 '15 at 18:21
  • 1
    @IanBush thanks, I'd forgotten about that. I've added that but kept the conditional compile part as a fallback on the off chance they are using an ancient compiler. – casey Sep 29 '15 at 18:25
  • Excellent! But I won't remove the comment as conditional compilation is EVIL!!!!!! (Sits back, awaits the comments)(But I honestly think this, it's just an even worse form of global variable) – Ian Bush Sep 29 '15 at 18:34
  • What about testing private functions and subroutines? I disagree with @IanBush about conticional compilation, for me it's the least intrussive solution. Some of us are stuck with Fortran 90... – astrojuanlu Dec 22 '15 at 15:33