I recently played around a bit with the various utPLSQL annotations and found them pretty powerful.
I’m pretty sure I will write some more about how you can use annotations like --%beforeall
or --%context
to make your tests more expressive, but today I just want to showcase some techniques and tell the story of the original Star Wars movies.
For the interesting part is completely in the package specification I will skip the body in the highlighted code here. Each procedure implementation only contains a call to dbms_output.put_line
with some text.
You can get the whole example as always from my github.
I create two test-packages, one parent package:
create or replace package sw_story_base as
-- %suite(Star Wars: Movies)
-- %beforeall
procedure in_a_galaxy_far_away;
-- %afterall
procedure the_good_wins;
procedure epic_intro;
-- %beforeeach
procedure deleted_scenes;
-- %aftereach(deleted_scenes)
end;
/
And one child package:
create or replace package sw_story_episode4_to_6 as
-- %suite(Episode IV-VI)
-- %suitepath(sw_story_base)
-- %beforeall
procedure clone_troops_are_bad;
-- %beforeall
procedure rebels_are_good;
-- %test(Scene: Construction plans of the deathstar are stolen (Rogue One))
-- %beforetest(sw_story_base.epic_intro)
-- %aftertest(rebels_flee)
procedure rogue_one;
-- %context(episode4)
-- %displayname(Episode IV - A New Hope)
-- %beforeall(sw_story_base.epic_intro)
-- %beforeeach(c3po_is_afraid)
-- %test(Scene: Rescue of princess Leia)
-- %aftertest(death_of_obiwan)
procedure rescue_of_leia;
procedure death_of_obiwan;
-- %test(Scene: Destruction of the deathstar)
procedure destroy_deathstar;
-- %aftereach
procedure c3po_is_relieved;
-- %endcontext
-- %context(episode5)
-- %displayname(Episode V - The Empire Strikes Back)
-- %beforeall(sw_story_base.epic_intro,rebels_flee)
-- %test(Scene: Battle for Hoth)
-- %aftertest(rebels_flee)
procedure battle_for_hoth;
-- %endcontext
-- %context(episode6)
-- %displayname(Episode VI - Return of the Jedi)
-- %beforeall(sw_story_base.epic_intro)
-- %beforeeach(c3po_is_afraid)
-- %aftereach(c3po_is_relieved)
-- %test(Scene: Battle for Endor)
procedure battle_for_endor;
-- %endcontext
procedure c3po_is_afraid;
procedure rebels_flee;
end;
/
Let’s look at the complete output of call ut.run(':sw_story_base')
(with set serveroutput on
) before I list some takeaways from this example
Star Wars: Movies
In a galaxy far, far away
Episode IV-VI
Context: Clone troops are bad
Context: Rebels are good
Episode VI - Return of the Jedi
An epic intro is shown
Scene: Battle for Endor [,001 sec]
C3PO is afraid
Cute teddy-bears totally own the imperial troops
C3PO is relieved
Episode V - The Empire Strikes Back
An epic intro is shown
The rebels have to flee
Scene: Battle for Hoth [,001 sec]
Imperium wins the battle for Hoth
The rebels have to flee
Episode IV - A New Hope
An epic intro is shown
Scene: Rescue of princess Leia [,002 sec]
C3PO is afraid
Luke, Han and Chewie find Leia and escape
Obi-Wan Kenobi dies
C3PO is relieved
Scene: Destruction of the deathstar [,001 sec]
C3PO is afraid
The deathstar is actually destroyed.
C3PO is relieved
Scene: Construction plans of the deathstar are stolen (Rogue One) [,001 sec]
An epic intro is shown
Rebels are able to steal the construction plans of the deathstar
The rebels have to flee
Finally, the good always wins.
If we draw some boxes around suites, contexts and tests and highlight the different outputs based on the annotation that made them appear, we get this:
Takeaway 1: “each”-annotations are not called in child-suites
Although we defined --%beforeeach
and --%aftereach
in the sw_story_base
suite, they are never called.
That is because there are no tests in the sw_story_base
suite, but only in the sw_story_episode4_to_6
, but beforeeach
and aftereach
are limited to tests of the same suite.
However, if they are defined on suite-level, they are also called for tests inside of contexts.
Takeaway 2: “before” and “after” annotations can be parameterized with method-references
All before
and after
annotations allow to be parameterized with references to procedures:
beforeall
beforeeach
beforetest
aftertest
aftereach
afterall
The referenced procedures don’t need to be in the same package but must be accessible.
Multiple references can be separated by comma and their order of execution is fixed.
Takeaway 3: You can reference the same method from different annotations
If you look at the rebels_flee
procedure, it is referenced from several different annotations: beforeall
and aftertest
.
There is no limitation how often or from which annotations you can reference a method.
As you can see with deleted_scenes
, you can even annotate a method with beforeeach
and additionally reference it as aftereach
(or any other before
or after
annotation).
Takeaway 4: You cannot rely on the order of contexts and tests, but on the order of setup and teardown
It’s obvious that our example messed up the order in which the different Episodes and Scenes are being called (there is even a new random test-execution functionality available since 3.1.7).
But the order in which the before
and after
methods are called is always fixed and you can totally rely on that.
So while you should aim to make tests and contexts independent from each other, you can guarantee their setup and teardown.
A request
I hope this little funny example showed you something new. If so, I’d love to hear about it.
But there’s another thing: I really wanted to create a little animation of that example-image where each step is highlighted together with the annotation that was used to call it. I sunk some hours trying to achieve it with PowerPoint but finally gave up frustrated.
If you know about any good and cheap tools that would help to explain stuff like this (for example by animated highlight/spotlight), please give me a hint.
0 Comments