|
1 | 1 | # Annotations |
2 | 2 |
|
3 | | -Annotations provide a way to configure tests and suites in a declarative way similar to modern OOP languages. |
4 | | -The annotation list is based on moder testing framework such as jUnit 5, RSpec. |
5 | | - |
6 | | -Annotations allow to configure test infrastructure in a declarative way without anything stored in tables or config files. The framework runner scans the schema for all the suitable annotated packages, automatically configures suites, forms hierarchy from then and executes them. |
| 3 | +Annotations provide a way to configure tests and suites in a declarative way similar to modern OOP languages. This way th behavior of tests stored along with the test logic, versioned using VCS with the code under test. No configuration files or tables are needed. The annotation list is based on popular testing frameworks such as jUnit 5 and RSpec. |
| 4 | +The framework runner searches for all the suitable annotated packages, automatically configures suites, forms suites hierarchy, executes it and reports results in differet formats. |
7 | 5 |
|
8 | 6 | Annotations are case-insensitive. But it is recommended to use the lower-case standard as described in the documentation. |
9 | 7 |
|
10 | | -Annotation on procedure level must be placed directly before the procedure name. |
| 8 | +There are two places where annotations may appear: at the beginning of the package specification (`%suite`, `%suitepath` etc) and right before a procedure (`%test`, `%beforeall`, `%beforeeach` etc). Package level annotations are separated by at least one empty line from the following procedure annotations. Procedure annotetions are defined right before the procedure they reference, no empty lines allowed. |
| 9 | + |
| 10 | +If a package conatins `%suite` annotation in its specification part it is treated as a test package and processed by the framework. |
11 | 11 |
|
12 | | -Annotation `-- %suite` should be placed at the beginning of package specification. It is not required but highly recommended as a practice. |
| 12 | +Some annotations accept parameters like `%suite`, `%test` `%displayname`, then the values are provided without any quatation marks, parameters are separated by commas. |
13 | 13 |
|
14 | 14 | # Example of annotated test package |
15 | 15 |
|
@@ -74,3 +74,77 @@ end test_pkg; |
74 | 74 | | `%aftertest(<procedure_name>)` | Procedure | Denotes that mentioned procedure should be executed after the annotated `%test` procedure. | |
75 | 75 | | `%rollback(<type>)` | Package/procedure | Configure transaction control behaviour (type). Supported values: `auto`(default) - rollback to savepoint (before the test/suite setup) is issued after each test/suite teardown; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | |
76 | 76 | | `%disabled` | Package/procedure | Used to disable a suite or a test | |
| 77 | + |
| 78 | +# Suitepath concept |
| 79 | +It is very likely that the application for which you are going to introduce tests consists of many different packages or procedures/functions. Usually procedures can be logically grouped inside a package, there also might be several logical groups of procedure in a single package or even packages themselves might relate to a common module. |
| 80 | + |
| 81 | +Lets say you have a complex insurance application the operates with policies, claims and payments. The payment module contains several packages for payment recognition, charging, planning etc. The payment recognition module among others contains a complex `recognize_payment` procedure that associates received money to the policies. |
| 82 | + |
| 83 | +If you want to create tests for your application it is recommended to structure your tests similarly to the logical structure of you application. So you end up with something like: |
| 84 | +* Integration tests |
| 85 | + * Policy tests |
| 86 | + * Claim tests |
| 87 | + * Payment tests |
| 88 | + * Payments recognition |
| 89 | + * Payments set off |
| 90 | + * Payouts |
| 91 | + |
| 92 | +The `%suitepath` annotation is used for such grouping. Even though test packages are defined in a flat structure the `%suitepath` is used by the framework to form a hierarchical structure of them. Your payments recognition test package might look like: |
| 93 | + |
| 94 | +```sql |
| 95 | +create or replace package test_payment_recognition as |
| 96 | + |
| 97 | + -- %suite(Payment recognition tests) |
| 98 | + -- %suitepath(payments) |
| 99 | + |
| 100 | + -- %test(Recognize payment by policy number) |
| 101 | + procedure test_recognize_by_num; |
| 102 | + |
| 103 | + -- %test |
| 104 | + -- %displayname(Recognize payment by payment purpose) |
| 105 | + procedure test_recognize_by_purpose; |
| 106 | + |
| 107 | + -- %test(Recognize payment by customer) |
| 108 | + procedure test_recognize_by_customer; |
| 109 | + |
| 110 | +end test_payment_recognition; |
| 111 | +``` |
| 112 | + |
| 113 | +And payments set off test package: |
| 114 | +```sql |
| 115 | +create or replace package test_payment_set_off as |
| 116 | + |
| 117 | + -- %suite(Payment set off tests) |
| 118 | + -- %suitepath(payments) |
| 119 | + |
| 120 | + -- %test(Set off creation test) |
| 121 | + procedure test_create_set_off; |
| 122 | + |
| 123 | + -- %test |
| 124 | + -- %displayname(Set off annulation test) |
| 125 | + procedure test_annulate_set_off; |
| 126 | + |
| 127 | +end test_payment_set_off; |
| 128 | +``` |
| 129 | + |
| 130 | +When you execute tests for your application, the framework constructs test suite for each test package. Then in combines suites into grouping suites by the `%suitepath` annotation value so that the fully qualified path to the `recognize_by_num` procedure is `USER:payments.test_payment_recognition.test_recognize_by_num`. If any of its expectations fails then the test is marked as failed, also the `test_payment_recognition` suite, the parent suite `payments` and the whole run is marked as failed. |
| 131 | +The test report indicates which expectation has failed on the payments module. The payments recognition submodule is causing the failure as `recognize_by_num` has is not meeting the expectations of the test. Grouping tests into modules and submodules using the `%suitepath` annotation allows you to logically organize your projects flat structure of packages int functional groups. |
| 132 | + |
| 133 | +Additional advantage of such grouping is the fact that every element level of the grouping can be an actual unit test package containing module level common setup for all of the submodules. So in addition to the packages mentioned above you could have following package. |
| 134 | +```sql |
| 135 | +create or replace package payments as |
| 136 | + |
| 137 | + -- %suite(Payments) |
| 138 | + |
| 139 | + -- %beforeall |
| 140 | + procedure set_common_payments_data; |
| 141 | + |
| 142 | + -- %afterall |
| 143 | + procedure reset_common_paymnets_data; |
| 144 | + |
| 145 | +end payments; |
| 146 | +``` |
| 147 | + |
| 148 | +A `%suitepath` is formed by valid sqlnames separated by dots. The depth of the suites path is not limited. The fully qualified path to a test is formed by `<user>:[<suitepath>.]<test package>.<test procedure>`. |
| 149 | + |
| 150 | +You can also use `%suitepath` to define the starting going of tests to execute. If you want to run only payments tests of the `FOO` schema then you gen execute `ut.run('foo:payments');` and all suites that have `payments` in their `%suitepath`s will be executed. This way you can filter the execution up to a single test. Only tests/suites which are children of the defined path are executed and all the parents `%beforeall`, `%beforeeach`, `%aftereach`, `%afterall` elements. So all the preparation and cleanup is performed as if you execute all the tests of the schema. |
0 commit comments