如何对其接口在子模块中定义的函数进行单元测试
How to unit test functions whose interfaces are defined within submodules
在我看来,子模块的一个不错的特性是您可以在子模块中创建辅助函数,而程序员的成本却非常低;您不会触发编译级联,不会弄乱命名空间或文档,并且可以立即清楚地知道该函数在哪里可以使用和不能使用。它们就像 private
函数的更好版本。
但是,子模块中的函数不能 use
d。虽然这是按预期工作的,但这似乎也阻止了对功能进行单元测试。我知道的两个单元测试框架 pFUnit and fruit 都需要 use
语法才能运行。
对于 How to access private variables in fortran modules? 中讨论的 private
函数的相同问题,有一些(恕我直言,有些不雅)解决方法,但这些解决方案中的 none 似乎适用于子模块中的函数,至少不是没有否定首先将这些功能放在子模块中的所有好处。
那么这个问题有什么解决办法吗?
引入 submodule
概念的主要目的是避免在模块文件中只引入了一个较小的非接口中断更改时出现长时间的重新编译级联。这是通过分离过程的接口并将它们放在父模块中并将实现保留在子模块中来完成的。
子模块本身允许有子模块,这对于非常大的情况很有用
程式。我见过的子模块的层级数一般不会超过两层(即一个模块有子模块本身也有子模块)但是没有限制。每个模块或子模块都是树的根,树的其他节点是它的后代,并且可以通过主机关联访问它。没有其他子模块有这样的访问权限,这有助于独立开发大型模块的一部分。此外,没有任何机制可以从其他地方访问子模块中声明的任何内容——正如您所说,它实际上是私有的。
因此,总而言之,如果您需要任何级别的任何子模块的任何内容被程序的任何其他部分访问,它必须在原始父模块中声明的子模块。据我所知,没有其他方法可以访问原始父模块中未给出接口或声明的任何子模块中的任何内容。
一旦将过程接口和 variable/type 声明放在父模块中,您就可以 use
它们在程序中的任何位置,即使过程实现可以埋在父模块的子模块中.
我对子模块没有什么经验(所以不确定这是否有用),但只是为了扩展我上面的评论...
!! 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
这是否有助于避免重新编译 parent_mod.f90(即使 parent_helper 或 parent_impl 被修改)? (而且我注意到模块名称“parent”在这里没有任何意义... XD)
在我看来,子模块的一个不错的特性是您可以在子模块中创建辅助函数,而程序员的成本却非常低;您不会触发编译级联,不会弄乱命名空间或文档,并且可以立即清楚地知道该函数在哪里可以使用和不能使用。它们就像 private
函数的更好版本。
但是,子模块中的函数不能 use
d。虽然这是按预期工作的,但这似乎也阻止了对功能进行单元测试。我知道的两个单元测试框架 pFUnit and fruit 都需要 use
语法才能运行。
对于 How to access private variables in fortran modules? 中讨论的 private
函数的相同问题,有一些(恕我直言,有些不雅)解决方法,但这些解决方案中的 none 似乎适用于子模块中的函数,至少不是没有否定首先将这些功能放在子模块中的所有好处。
那么这个问题有什么解决办法吗?
引入 submodule
概念的主要目的是避免在模块文件中只引入了一个较小的非接口中断更改时出现长时间的重新编译级联。这是通过分离过程的接口并将它们放在父模块中并将实现保留在子模块中来完成的。
子模块本身允许有子模块,这对于非常大的情况很有用 程式。我见过的子模块的层级数一般不会超过两层(即一个模块有子模块本身也有子模块)但是没有限制。每个模块或子模块都是树的根,树的其他节点是它的后代,并且可以通过主机关联访问它。没有其他子模块有这样的访问权限,这有助于独立开发大型模块的一部分。此外,没有任何机制可以从其他地方访问子模块中声明的任何内容——正如您所说,它实际上是私有的。
因此,总而言之,如果您需要任何级别的任何子模块的任何内容被程序的任何其他部分访问,它必须在原始父模块中声明的子模块。据我所知,没有其他方法可以访问原始父模块中未给出接口或声明的任何子模块中的任何内容。
一旦将过程接口和 variable/type 声明放在父模块中,您就可以 use
它们在程序中的任何位置,即使过程实现可以埋在父模块的子模块中.
我对子模块没有什么经验(所以不确定这是否有用),但只是为了扩展我上面的评论...
!! 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
这是否有助于避免重新编译 parent_mod.f90(即使 parent_helper 或 parent_impl 被修改)? (而且我注意到模块名称“parent”在这里没有任何意义... XD)