Skip to content

Commit e021663

Browse files
committed
WIP: first draft of explaining parameterised test syntax
1 parent 797787e commit e021663

1 file changed

Lines changed: 105 additions & 4 deletions

File tree

episodes/4-pfunit-syntax.md

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ end module test_dot_product_intrinsic
113113

114114
## Handling state within tests
115115

116-
If the code we wished to test required some state to be setup prior to running the test, such as allocating arrays, we could repeat this step within each test, like so:
116+
If multiple tests rely of the existence of some state such as the allocation of an array. We could repeat this step within each test, like so:
117117

118118
```fortran
119119
module test_dot_product_intrinsic
@@ -382,8 +382,109 @@ The key features of this the type **dot_product_test_parameters** are
382382
- It is decorated with the directive **@TestParameter**.
383383
- It extends the type **AbstractTestParameter** provided by the pFUnit library.
384384
- All inputs (**a** and **b**) and expected outputs (**expected_dot_product**) of **dot_product** are define as type-bound variables.
385-
- There is an extra type-bound variable - **description** - which is used alongside the type-bound procedure **toString => dot_product_test_parameters_toString**.
386-
- pFUnit requires that a type which extends **AbstractTestParameter** defines a type-bound procedure called **toString**. This procedure is then used to provide a description of the specific parameter set within the name of each test.
387-
- For simplicity, we have added the variable **description** which we can be defined and return from **dot_product_test_parameters_toString** (we will cover this shortly).
385+
- The type-bound variable **description** and procedure **toString** allow conversion of a single test parameter instance to a character array for logging (see below).
386+
387+
#### toString
388+
389+
pFUnit requires that a type which extends **AbstractTestParameter** must define a type-bound procedure called **toString**:
390+
391+
```fortran
392+
!> Trims and returns the description of the parameter set. The string returned
393+
!> by this function will be included by pFUnit in the name of this test
394+
function toString(this) result(string)
395+
class (dot_product_test_parameters), intent(in) :: this
396+
character(:), allocatable :: string
397+
398+
string = trim(this%description)
399+
end function toString
400+
```
401+
402+
For simplicity, we utilise the variable **description** to define this string in its entirity.
403+
404+
:::::::::: callout
405+
406+
#### Default type constructor
407+
408+
All derived types in Fortran are given a default constructor of the same name which can be invoked
409+
like a function. For example, we can create an instance of our type **dot_product_test_parameters**
410+
like so:
411+
412+
```fortran
413+
type(dot_product_test_parameters) :: testParameters
414+
415+
testParameters = dot_product_test_parameters(a, b, expected_dot_product, "10x10 incrementing values")
416+
```
417+
418+
::::::::::::::::::
419+
420+
::::::::::::
421+
422+
:::::::::::: spoiler
423+
424+
### 2. Parameterising the test case
425+
426+
Now that we have a new test parameter type, we must update our test case type to make use of it:
427+
428+
```fortran
429+
!> Custom test case type allowing a single definition of tearDown logic.
430+
!! If teardown is not required, This could also be thought of as boilerplate
431+
!! required to make the parameters available within our @Test.
432+
@TestCase(constructor=dot_product_test_case_constructor)
433+
type, extends(ParameterizedTestCase) :: dot_product_test_case
434+
!> The instance of our test parameters type to be used within the test logic
435+
type(dot_product_test_parameters) :: params
436+
contains
437+
procedure :: tearDown
438+
end type dot_product_test_case
439+
```
440+
441+
The key points to highlight are:
442+
443+
- We are now extending the base type **ParameterizedTestCase**.
444+
- To prevent duplication we simply define an instance of our test parameter type as a type-bound variable.
445+
- The type-bound procedure **teardown** remains the same.
446+
447+
#### Test case constructor
448+
449+
Whilst **teardown** remains almost unchanged, **dot_product_test_case_constructor** has changed considerably.
450+
We now no longer use this as a mechanism to setup state but instead we are converting an instance of our parameter
451+
type (**dot_product_test_parameters**) into an instance of our test case type (**dot_product_test_case**).
452+
453+
```f90
454+
!> Boilerplate constructor required to convert our custom parameters type to
455+
!! the test case type.
456+
function dot_product_test_case_constructor(testParameters) result(newTestCase)
457+
type(dot_product_test_parameters), intent(in) :: testParameters
458+
type(dot_product_test_case) :: newTestCase
459+
460+
newTestCase%params = testParameters
461+
end function dot_product_test_case_constructor
462+
```
463+
464+
:::::::::::: callout
465+
466+
#### Setting up state
467+
468+
Now that we are not using the test case constructor for setting up state we need a new place for this to be done.
469+
Thankfully, pFUnit allows us to do this in similar way to **teardown** by adding a new type-bound procedure within
470+
our test case type called **setUp**.
471+
472+
::::::::::::::::::::
473+
474+
:::::::::::: spoiler
475+
476+
### 3. Defining a suite of tests / parameter sets
477+
478+
**TODO:**
479+
- Returns a list of parameter sets where each set represents a single test
480+
- If inputs need to be allocated, this is where we do it.
481+
482+
::::::::::::
483+
484+
:::::::::::: spoiler
485+
486+
### 4. Passing the test suite into the @Test
487+
488+
::::::::::::
388489

389490
::::::::::::

0 commit comments

Comments
 (0)