Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: Update unit test guidance #559

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions docs/source/testing/unit_test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ This framework provides a Fortran abstraction to the popular
along with OpenFAST through CMake when the CMake variable ``BUILD_TESTING`` is
turned on.

The BeamDyn module has been unit tested and should serve as a reference for
future development and testing.
The BeamDyn and NWTC Library modules contain some sample unit tests and should
serve as a reference for future development and testing.

Dependencies
------------
Expand All @@ -38,15 +38,15 @@ framework named ``[module]_utest``. Then, ``make`` the target to test:
make beamdyn_utest

This creates a unit test executable at
``openfast/build/unit_tests/beamdyn_utest``.
``openfast/build/unit_tests/beamdyn/beamdyn_utest``.

Executing
---------
To execute a module's unit test, simply run the unit test binary. For example:

.. code-block:: bash

>>>$ ./openfast/build/unit_tests/beamdyn_utest
>>>$ ./openfast/build/unit_tests/beamdyn/beamdyn_utest
.............
Time: 0.018 seconds

Expand All @@ -60,7 +60,7 @@ the failure. Failure cases display the following output:

.. code-block:: bash

>>>$ ./unit_tests/beamdyn_utest
>>>$ ./unit_tests/beamdyn/beamdyn_utest
.....F.......
Time: 0.008 seconds

Expand Down Expand Up @@ -91,27 +91,31 @@ or function). What is testable is the discretion of the developer, but an
element of the pull request review process will be evaluating test coverage.

New unit tests can be added to a ``tests`` directory alongside the ``src``
directory included in each module. For example, the BeamDyn module directory is
directory included in each module. For example, a module directory may be
structured as

::

openfast/
└── modules/
└── beamdyn/
└── sampledyn/
├── src/
│ ├── BeamDyn.f90
│ └── BeamDyn_Subs.f90
│ ├── SampleDyn.f90
│ └── SampleDyn_Subs.f90
└── tests/
├── test_BD_Subroutine1.F90
├── test_BD_Subroutine2.F90
└── test_BD_Subroutine3.F90
├── test_SampleDyn_Subroutine1.F90
├── test_SampleDyn_Subroutine2.F90
└── test_SampleDyn_Subroutine3.F90

Each unit test must be contained in a unique file called
``test_[SUBROUTINE].F90`` where ``[SUBROUTINE]`` is the code block being
tested. Finally, update the CMake configuration for building a module's unit
test executable by copying the BeamDyn CMake configuration into a new module
directory:
tested. The new files should contain a Fortran `module` which itself
contains a Fortran `subroutine` for each specific test case. Generally,
multiple tests will be required to fully test one subroutine.

Finally, update the CMake configuration for building a module's unit
test executable by copying an existing unit test CMake configuration
into a new module directory:

.. code-block:: bash

Expand Down
138 changes: 83 additions & 55 deletions unit_tests/test_SUBROUTINE.F90
Original file line number Diff line number Diff line change
@@ -1,61 +1,89 @@
@test
subroutine test_SUBROUTINE()
! test branches
module test_SUBROUTINE

use pFUnit_mod
use NWTC_IO
! use MODULE ! Import the module that will be tested here.

implicit none

real(ReKi) :: tolerance = 1e-14
character(1024) :: testname

contains

! Test branches
! - branch 1
! - branch 2
! - branch 3

! Note that this subroutine is *not* conforming Fortran code.
! Note that this module is *not* conforming Fortran code.
! This is passed through a Python preprocessor included with pFUnit which parses
! pFUnit directives like `@test` and `@assertEqual` to generate proper Fortran code.

use pFUnit_mod
use NWTC_Num

implicit none

integer :: flag
character(1024) :: testname
real(BDKi) :: tolerance

! initialize NWTC_Num constants
call SetConstants()

tolerance = 1e-14

! --------------------------------------------------------------------------
testname = "branch 1:"

! describe this test
! what is the expected result from the test subroutine
! how are the baselines obtained

call SUBROUTINE()

@assertEqual(baseline, test, tolerance, testname)


! --------------------------------------------------------------------------
testname = "branch 2:"

! describe this test
! what is the expected result from the test subroutine
! how are the baselines obtained

call SUBROUTINE()

@assertEqual(baseline, test, tolerance, testname)


! --------------------------------------------------------------------------
testname = "branch 3:"

! describe this test
! what is the expected result from the test subroutine
! how are the baselines obtained

call SUBROUTINE()

@assertEqual(baseline, test, tolerance, testname)

end subroutine

@test
subroutine test_branch1()

! Describe this test.
! What is the expected result from the tested subroutine?
! Why is the expected result the result that is expected?

real(ReKi) :: zero = 0.0
real(ReKi) :: test_result
integer(IntKi) :: error_status

testname = "Branch 1"
expected = 0.0

! Assume SUBROUTINE( intent(in), intent(out), intent(out) )
call SUBROUTINE(zero, test_result, error_status)

@assertEqual(expected, test_result, tolerance, testname)
@assertEqual(0, error_status, tolerance, testname)

end subroutine

@test
subroutine test_branch2()

! Describe this test.
! What is the expected result from the tested subroutine?
! Why is the expected result the result that is expected?

real(ReKi) :: pi = 3.14159
real(ReKi) :: test_result
integer(IntKi) :: error_status

testname = "Branch 2"
expected = 0.0

! Assume SUBROUTINE( intent(in), intent(out), intent(out) )
call SUBROUTINE(pi, test_result, error_status)

@assertEqual(expected, test_result, tolerance, testname)
@assertEqual(0, error_status, tolerance, testname)

end subroutine

@test
subroutine test_branch3()

! Describe this test.
! What is the expected result from the tested subroutine?
! Why is the expected result the result that is expected?

real(ReKi) :: pi_by_2 = 1.57079
real(ReKi) :: test_result
integer(IntKi) :: error_status

testname = "Branch 3"
expected = 99.9

! Assume SUBROUTINE( intent(in), intent(out), intent(out) )
call SUBROUTINE(pi_by_2, test_result, error_status)

@assertEqual(expected, test_result, tolerance, testname)
@assertEqual(0, error_status, tolerance, testname)

end subroutine

end module