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
--%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
--%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
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
after annotations allow to be parameterized with references to procedures:
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:
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
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
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.
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.