Skip to content

Commit 56a3e13

Browse files
committed
Adding unit testing walkthrough.
1 parent d5c1fbd commit 56a3e13

File tree

1 file changed

+158
-1
lines changed

1 file changed

+158
-1
lines changed

docs/conversion/walkthrough.md

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,164 @@ Bug gets extremely lucky (or maybe he's just really skilled) and there are no di
690690
Bug commits his changes to his fork/branch of the three repos: CAM, CAM-SIMA, atmospheric_physics.
691691

692692
### Unit testing
693-
Bug adds PfUnit tests for his newly-created scheme per the [atmospheric_physics development workflow](../atmospheric_physics/development_workflow.md#5-unit-testing).
693+
694+
Lets say you added a utility function in `physics_tendency_updaters.F90
695+
` to apply the pressure tendency of the atmosphere:
696+
697+
```fortran
698+
subroutine apply_tendency_of_air_pressure_run(nz, p_tend, pressure, dPdt_total, &
699+
dt, errcode, errmsg)
700+
! Dummy arguments
701+
integer, intent(in) :: nz ! Num vertical layers
702+
real(kind_phys), intent(in) :: p_tend(:,:) ! pressure tendency
703+
real(kind_phys), intent(inout) :: pressure(:,:) ! air pressure
704+
real(kind_phys), intent(inout) :: dPdt_total(:,:) ! total temp. tendency
705+
real(kind_phys), intent(in) :: dt ! physics time step
706+
integer, intent(out) :: errcode
707+
character(len=512), intent(out) :: errmsg
708+
709+
! Local variable
710+
integer :: klev
711+
712+
errcode = 0
713+
errmsg = ''
714+
715+
do klev = 1, nz
716+
pressure(:, klev) = pressure(:, klev) + (p_tend(:, klev) * dt)
717+
dPdt_total(:, klev) = dPdt_total(:, klev) + p_tend(:, klev)
718+
end do
719+
720+
end subroutine apply_tendency_of_air_pressure_run
721+
```
722+
723+
Then you would need to check that the file you've modified is being built by the tests. You can check this in `test/unit-test/CMakeLists.txt` and see that we have:
724+
725+
```cmake
726+
set(UTILITIES_SRC
727+
../../schemes/utilities/state_converters.F90
728+
../../schemes/utilities/static_energy.F90
729+
../../schemes/utilities/physics_tendency_updaters.F90
730+
include/ccpp_kinds.F90
731+
)
732+
```
733+
734+
Since the file is being built, we don't have to add to this list.
735+
736+
Next we look for `test/unit-test/tests/utilities/CMakeLists.txt` to see if there is a matching test file:
737+
738+
```sh
739+
$ ls cat test/unit-test/tests/utilities/
740+
CMakeLists.txt
741+
test_state_converters.pf
742+
$
743+
$ cat test/unit-test/tests/utilities/CMakeLists.txt
744+
add_pfunit_ctest(utilities_tests
745+
TEST_SOURCES test_state_converters.pf
746+
LINK_LIBRARIES utilities
747+
)
748+
$
749+
```
750+
751+
Because there is no matching file or test, we need to create it:
752+
753+
```sh
754+
$ cat > test/unit-test/tests/utilities/test_physics_tendency_updaters.pf << EOF
755+
@test
756+
subroutine test_pressure_tendency_update()
757+
use funit
758+
use physics_tendency_updaters
759+
760+
end subroutine test_pressure_tendency_update
761+
EOF
762+
```
763+
764+
And add the ability to build/run it from the test harness by updating `test/unit-test/tests/utilities/CMakeLists.txt`:
765+
766+
```
767+
add_pfunit_ctest(utilities_tests
768+
TEST_SOURCES test_state_converters.pf test_physics_tendency_updaters.pf
769+
LINK_LIBRARIES utilities
770+
```
771+
where `test_physics_tendency_updaters.pf` has been added to the `TEST_SOURCES` list.
772+
773+
Now, to actually test the function, we can try something like:
774+
775+
```fortran
776+
@test
777+
subroutine test_pressure_tendency_update()
778+
use funit
779+
use ccpp_kinds, only: kind_phys
780+
use physics_tendency_updaters
781+
782+
# Declare and setup test data with known results
783+
784+
integer, parameter :: ncol = 3 ! Num columns
785+
integer, parameter :: nz = 3 ! Num vertical layers
786+
integer, parameter :: errcode = 0
787+
character(len=512), parameter :: errmsg = ''
788+
789+
real(kind_phys) :: p_tend(ncol, nz) ! pressure tendency
790+
real(kind_phys) :: pressure(ncol, nz) ! air pressure
791+
real(kind_phys) :: dPdt_total(nol, nz) ! total temp. tendency
792+
real(kind_phys) :: dt ! physics time step
793+
794+
pressure = 1
795+
p_tend = 1
796+
dPdt_total = 0
797+
dt = 1
798+
799+
call apply_tendency_of_air_pressure_run(nz, p_tend, pressure, &
800+
dPdt_total, dt, &
801+
errcode, errmsg)
802+
803+
@assertEqual(2, pressure)
804+
@assertEqual(1, dPdt_total)
805+
@assertEqual(0, errcode)
806+
@assertEqual('', errmsg)
807+
end subroutine test_pressure_tendency_update
808+
```
809+
810+
The values should be scientifically relevant to test a valid physics case or be set up to test edge cases that the subroutine must support.
811+
812+
Notice that we are only testing `intent(out)` and `intent(inout)` as these are the only values that can change.
813+
814+
Assuming you have built the test framework according to the [instructions](../atmospheric_physics/development_workflow.md#5-unit-testing), you can now run:
815+
816+
```bash
817+
$ cmake \
818+
-DCMAKE_PREFIX_PATH=<PATH_TO_PFUNIT>/build/installed \
819+
-DATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE=ON \
820+
-B./build \
821+
-S./test/unit-test
822+
$ cd build
823+
$ make
824+
$ ctest -V --output-on-failure
825+
```
826+
827+
After which you should see output similar to:
828+
829+
```
830+
1: Start: <test_state_converters_suite.test_temp_to_potential_temp>
831+
1: . end: <test_state_converters_suite.test_temp_to_potential_temp>
832+
1:
833+
1: Time: 0.000 seconds
834+
1:
835+
1: OK
836+
1: (1 test)
837+
1:
838+
2: Start: <test_physics_tendency_updaters_suite.test_pressure_tendency_update>
839+
2: . end: <test_physics_tendency_updaters_suite.test_pressure_tendency_update>
840+
2:
841+
2: Time: 0.000 seconds
842+
2:
843+
2: OK
844+
2: (1 test)
845+
2/2 Test #1: utilities_tests .................. Passed 0.00 sec
846+
847+
100% tests passed, 0 tests failed out of 1
848+
```
849+
850+
If 100% of the tests pass, you may proceed to the next section.
694851

695852
### Pull Requests
696853
- He opens a PR into atmospheric_physics (target: `development` branch), goes through the review process, updates the NamesNotInDictionary.txt file, and then commits the PR when approvals are received. He then opens a PR from `development` to `main` and makes a tag (incrementing the minor version) when that is merged.

0 commit comments

Comments
 (0)