From e926425dc1a30cd4f3cf8ae4ef44f46741451055 Mon Sep 17 00:00:00 2001 From: Pazus Date: Sat, 4 Feb 2017 13:19:50 +0300 Subject: [PATCH 01/16] fix for invalid package v2 --- source/core/types/ut_logical_suite.tpb | 16 ++--- source/core/types/ut_logical_suite.tps | 1 - source/core/types/ut_run.tpb | 6 -- source/core/types/ut_run.tps | 1 - source/core/types/ut_suite.tpb | 91 ++++++++++++++------------ source/core/types/ut_suite_item.tpb | 6 ++ source/core/types/ut_suite_item.tps | 2 +- source/core/types/ut_test.tpb | 6 -- source/core/types/ut_test.tps | 1 - 9 files changed, 63 insertions(+), 67 deletions(-) diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index d7ab7423d..3f87edf84 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -36,39 +36,35 @@ create or replace type body ut_logical_suite as self.items(self.items.last) := a_item; end; - overriding member procedure do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) is - l_completed_without_errors boolean; - begin - l_completed_without_errors := self.do_execute(a_listener); - end; - overriding member function do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) return boolean is l_suite_savepoint varchar2(30); l_item_savepoint varchar2(30); l_completed_without_errors boolean; begin ut_utils.debug_log('ut_logical_suite.execute'); + + a_listener.fire_before_event(ut_utils.gc_suite,self); + self.start_time := current_timestamp; if self.get_ignore_flag() then self.result := ut_utils.tr_ignore; + self.end_time := self.start_time; ut_utils.debug_log('ut_logical_suite.execute - ignored'); else - a_listener.fire_before_event(ut_utils.gc_suite,self); self.start_time := current_timestamp; for i in 1 .. self.items.count loop -- execute the item (test or suite) self.items(i).do_execute(a_listener); - end loop; self.calc_execution_result(); - self.end_time := current_timestamp; - a_listener.fire_after_event(ut_utils.gc_suite,self); end if; + + a_listener.fire_after_event(ut_utils.gc_suite,self); return l_completed_without_errors; end; diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index 436496545..fd001be83 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -15,7 +15,6 @@ create or replace type ut_logical_suite force under ut_suite_item ( member function item_index(a_name varchar2) return pls_integer, member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item), overriding member function do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) return boolean, - overriding member procedure do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base), overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite) ) not final / diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 3762f897b..141cde2a9 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -8,12 +8,6 @@ create or replace type body ut_run as return; end; - overriding member procedure do_execute(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base) is - l_completed_without_errors boolean; - begin - l_completed_without_errors := self.do_execute(a_listener); - end; - overriding member function do_execute(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base) return boolean is l_completed_without_errors boolean; begin diff --git a/source/core/types/ut_run.tps b/source/core/types/ut_run.tps index 7cb22ad72..1019152d0 100644 --- a/source/core/types/ut_run.tps +++ b/source/core/types/ut_run.tps @@ -5,7 +5,6 @@ create or replace type ut_run authid current_user under ut_suite_item ( items ut_suite_items, constructor function ut_run( self in out nocopy ut_run, a_items ut_suite_items ) return self as result, overriding member function do_execute(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base) return boolean, - overriding member procedure do_execute(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base), overriding member procedure calc_execution_result(self in out nocopy ut_run) ) / diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 082987c3d..629f7b489 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -33,61 +33,70 @@ create or replace type body ut_suite as l_completed_without_errors boolean; begin ut_utils.debug_log('ut_suite .execute'); + a_listener.fire_before_event(ut_utils.gc_suite,self); + + self.start_time := current_timestamp; if self.get_ignore_flag() then self.result := ut_utils.tr_ignore; + self.end_time := self.start_time; ut_utils.debug_log('ut_suite .execute - ignored'); else - a_listener.fire_before_event(ut_utils.gc_suite,self); - - self.start_time := current_timestamp; - - l_suite_savepoint := self.create_savepoint_if_needed(); - - --includes listener calls for before and after actions - l_completed_without_errors := self.before_all.do_execute(self, a_listener); - - if l_completed_without_errors then - for i in 1 .. self.items.count loop - l_completed_without_errors := true; - - --savepoint - l_item_savepoint := self.items(i).create_savepoint_if_needed(); - --before each - if l_completed_without_errors then - --includes listener calls for before and after actions - l_completed_without_errors := self.before_each.do_execute(self, a_listener); - end if; - - -- execute the item (test or suite) - if l_completed_without_errors then + + if self.is_valid() then + + l_suite_savepoint := self.create_savepoint_if_needed(); + + --includes listener calls for before and after actions + l_completed_without_errors := self.before_all.do_execute(self, a_listener); + + if l_completed_without_errors then + for i in 1 .. self.items.count loop + l_completed_without_errors := true; + + --savepoint + l_item_savepoint := self.items(i).create_savepoint_if_needed(); + --before each + if l_completed_without_errors then + --includes listener calls for before and after actions + l_completed_without_errors := self.before_each.do_execute(self, a_listener); + end if; + + -- execute the item (test or suite) + if l_completed_without_errors then + l_completed_without_errors := self.items(i).do_execute(a_listener); + end if; + + --after each + if l_completed_without_errors then + --includes listener calls for before and after actions + l_completed_without_errors := self.after_each.do_execute(self, a_listener); + end if; + --rollback to savepoint + self.items(i).rollback_to_savepoint(l_item_savepoint); + + -- exit when not l_completed_without_errors; + end loop; + end if; + + if l_completed_without_errors then + l_completed_without_errors := self.after_all.do_execute(self, a_listener); + end if; + + self.rollback_to_savepoint(l_suite_savepoint); + else + for i in 1..self.items.count loop + if self.items(i) is of(ut_test) then l_completed_without_errors := self.items(i).do_execute(a_listener); end if; - - --after each - if l_completed_without_errors then - --includes listener calls for before and after actions - l_completed_without_errors := self.after_each.do_execute(self, a_listener); - end if; - --rollback to savepoint - self.items(i).rollback_to_savepoint(l_item_savepoint); - --- exit when not l_completed_without_errors; end loop; end if; - if l_completed_without_errors then - l_completed_without_errors := self.after_all.do_execute(self, a_listener); - end if; - self.calc_execution_result(); - - self.rollback_to_savepoint(l_suite_savepoint); - self.end_time := current_timestamp; - a_listener.fire_after_event(ut_utils.gc_suite,self); end if; + a_listener.fire_after_event(ut_utils.gc_suite,self); return l_completed_without_errors; end; diff --git a/source/core/types/ut_suite_item.tpb b/source/core/types/ut_suite_item.tpb index 9b2160e67..cecca6bab 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -24,6 +24,12 @@ create or replace type body ut_suite_item as begin return ut_utils.int_to_boolean(self.ignore_flag); end; + + final member procedure do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) is + l_completed_without_errors boolean; + begin + l_completed_without_errors := self.do_execute(a_listener); + end; member function create_savepoint_if_needed return varchar2 is l_savepoint varchar2(30); diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index da120d830..487e8d52c 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -11,7 +11,7 @@ create or replace type ut_suite_item under ut_suite_item_base ( member function execution_time return number, not instantiable member function do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) return boolean, - not instantiable member procedure do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base), + final member procedure do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base), not instantiable member procedure calc_execution_result(self in out nocopy ut_suite_item) ) diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index 5e847d5f3..7a8407403 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -23,12 +23,6 @@ create or replace type body ut_test as return l_is_valid; end; - overriding member procedure do_execute(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base) is - l_completed_without_errors boolean; - begin - l_completed_without_errors := self.do_execute(a_listener); - end; - overriding member function do_execute(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base) return boolean is l_completed_without_errors boolean; l_savepoint varchar2(30); diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index 247f8b8e4..3a1800f4f 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -23,7 +23,6 @@ create or replace type ut_test under ut_suite_item ( a_path varchar2 := null, a_rollback_type integer := null, a_ignore_flag boolean := false, a_before_test_proc_name varchar2 := null, a_after_test_proc_name varchar2 := null ) return self as result, member function is_valid return boolean, - overriding member procedure do_execute(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base), overriding member function do_execute(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_test) ) From 7840258e2db560a20b28ecb69d4a776a0a94b6b1 Mon Sep 17 00:00:00 2001 From: Pazus Date: Mon, 6 Feb 2017 00:04:17 +0300 Subject: [PATCH 02/16] teststep --- source/core/types/ut_run.tpb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 7cef0e32d..192f2074f 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -32,6 +32,9 @@ create or replace type body ut_run as a_listener.fire_before_event(ut_utils.gc_run, self); self.start_time := current_timestamp; + + -- clear anything that might stay in the session's cache + ut_assert_processor.clear_asserts; for i in 1 .. self.items.count loop l_completed_without_errors := self.items(i).do_execute(a_listener); From 40a9b444d1ce3d352a9f452a92c0dc9abc54ba73 Mon Sep 17 00:00:00 2001 From: Pazus Date: Wed, 8 Feb 2017 21:26:26 +0300 Subject: [PATCH 03/16] implemented `fail` procedure at ut_test_item level to push failures to child items --- source/core/types/ut_logical_suite.tpb | 16 +++++++- source/core/types/ut_logical_suite.tps | 5 ++- source/core/types/ut_run.tpb | 17 ++++++++ source/core/types/ut_run.tps | 5 ++- source/core/types/ut_suite.tpb | 56 ++++++++++++++++---------- source/core/types/ut_suite_item.tps | 3 +- source/core/types/ut_test.tpb | 12 ++++++ source/core/types/ut_test.tps | 3 +- source/core/ut_suite_manager.pkb | 1 + 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index e84f0ccd9..da9c1f28b 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -99,7 +99,21 @@ create or replace type body ut_logical_suite as end if; self.result := l_result; - end; + end; + + overriding member procedure fail(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) is + begin + ut_utils.debug_log('ut_logical_suite.fail'); + a_listener.fire_before_event(ut_utils.gc_suite, self); + self.start_time := current_timestamp; + for i in 1 .. self.items.count loop + -- execute the item (test or suite) + self.items(i).fail(a_listener,a_failure_msg); + end loop; + self.calc_execution_result(); + self.end_time := self.start_time; + a_listener.fire_after_event(ut_utils.gc_suite, self); + end; end; / diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index bc1df481c..e90e51589 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -1,4 +1,4 @@ -create or replace type ut_logical_suite force under ut_suite_item ( +create or replace type ut_logical_suite under ut_suite_item ( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -31,6 +31,7 @@ create or replace type ut_logical_suite force under ut_suite_item ( member function item_index(a_name varchar2) return pls_integer, member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item), overriding member function do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) return boolean, - overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite) + overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite), + overriding member procedure fail(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) ) not final / diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 192f2074f..815af3357 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -64,6 +64,23 @@ create or replace type body ut_run as self.result := l_result; end; + + overriding member procedure fail(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) is + begin + ut_utils.debug_log('ut_run.fail'); + + a_listener.fire_before_event(ut_utils.gc_run, self); + self.start_time := current_timestamp; + + for i in 1 .. self.items.count loop + self.items(i).fail(a_listener, a_failure_msg); + end loop; + + self.calc_execution_result(); + self.end_time := self.start_time; + + a_listener.fire_after_event(ut_utils.gc_run, self); + end; end; / diff --git a/source/core/types/ut_run.tps b/source/core/types/ut_run.tps index 6c5a61c93..d552d2be3 100644 --- a/source/core/types/ut_run.tps +++ b/source/core/types/ut_run.tps @@ -1,4 +1,4 @@ -create or replace type ut_run authid current_user under ut_suite_item ( +create or replace type ut_run under ut_suite_item ( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -21,6 +21,7 @@ create or replace type ut_run authid current_user under ut_suite_item ( items ut_suite_items, constructor function ut_run( self in out nocopy ut_run, a_items ut_suite_items ) return self as result, overriding member function do_execute(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base) return boolean, - overriding member procedure calc_execution_result(self in out nocopy ut_run) + overriding member procedure calc_execution_result(self in out nocopy ut_run), + overriding member procedure fail(self in out nocopy ut_run, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) ) / diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 883acc471..c282f4bcb 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -43,12 +43,21 @@ create or replace type body ut_suite as return l_is_valid; end; - overriding member function do_execute(self in out nocopy ut_suite , a_listener in out nocopy ut_event_listener_base) return boolean is + overriding member function do_execute(self in out nocopy ut_suite, a_listener in out nocopy ut_event_listener_base) return boolean is l_suite_savepoint varchar2(30); l_item_savepoint varchar2(30); l_completed_without_errors boolean; + l_suite_step_without_errors boolean; + + procedure do_fail(a_prefix varchar2) is + l_results ut_assert_results := ut_assert_processor.get_asserts_results(); + begin + for i in 1..self.items.count loop + self.items(i).fail(a_listener, a_prefix||l_results(1).error_message); + end loop; + end; begin - ut_utils.debug_log('ut_suite .execute'); + ut_utils.debug_log('ut_suite.execute'); a_listener.fire_before_event(ut_utils.gc_suite,self); self.start_time := current_timestamp; @@ -64,48 +73,53 @@ create or replace type body ut_suite as l_suite_savepoint := self.create_savepoint_if_needed(); --includes listener calls for before and after actions - l_completed_without_errors := self.before_all.do_execute(self, a_listener); + l_suite_step_without_errors := self.before_all.do_execute(self, a_listener); - if l_completed_without_errors then + if l_suite_step_without_errors then for i in 1 .. self.items.count loop l_completed_without_errors := true; --savepoint l_item_savepoint := self.items(i).create_savepoint_if_needed(); --before each - if l_completed_without_errors then - --includes listener calls for before and after actions - l_completed_without_errors := self.before_each.do_execute(self, a_listener); - end if; + --includes listener calls for before and after actions + l_completed_without_errors := self.before_each.do_execute(self, a_listener); -- execute the item (test or suite) if l_completed_without_errors then l_completed_without_errors := self.items(i).do_execute(a_listener); - end if; - - --after each - if l_completed_without_errors then + + --after each --includes listener calls for before and after actions + -- run afteeach even if a test raised an exception l_completed_without_errors := self.after_each.do_execute(self, a_listener); + + if not l_completed_without_errors then + self.items(i).fail(a_listener, 'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); + end if; + + else + self.items(i).fail(a_listener, 'Beforeach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); end if; + --rollback to savepoint self.items(i).rollback_to_savepoint(l_item_savepoint); -- exit when not l_completed_without_errors; end loop; - end if; - - if l_completed_without_errors then - l_completed_without_errors := self.after_all.do_execute(self, a_listener); + + l_suite_step_without_errors := self.after_all.do_execute(self, a_listener); + if not l_suite_step_without_errors then + do_fail('Afterall procedure failed: '||chr(10)); + end if; + else + do_fail('Beforeall procedure failed: '||chr(10)); end if; self.rollback_to_savepoint(l_suite_savepoint); + else - for i in 1..self.items.count loop - if self.items(i) is of(ut_test) then - l_completed_without_errors := self.items(i).do_execute(a_listener); - end if; - end loop; + do_fail(null); end if; self.calc_execution_result(); diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 7f3086322..3831d3eeb 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -28,7 +28,8 @@ create or replace type ut_suite_item under ut_suite_item_base ( not instantiable member function do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) return boolean, final member procedure do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base), - not instantiable member procedure calc_execution_result(self in out nocopy ut_suite_item) + not instantiable member procedure calc_execution_result(self in out nocopy ut_suite_item), + not instantiable member procedure fail(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) ) not final not instantiable diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index c2661a48d..e8d1717d4 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -87,6 +87,18 @@ create or replace type body ut_test as self.results := ut_assert_processor.get_asserts_results(); self.results_count := ut_results_counter(self.result); end; + + overriding member procedure fail(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) is + begin + ut_utils.debug_log('ut_test.fail'); + a_listener.fire_before_event(ut_utils.gc_test, self); + self.start_time := current_timestamp; + ut_assert_processor.report_error(a_failure_msg); + self.calc_execution_result(); + self.end_time := self.start_time; + a_listener.fire_after_event(ut_utils.gc_test, self); + end; + end; / diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index 2bd77b75e..371c53bce 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -40,6 +40,7 @@ create or replace type ut_test under ut_suite_item ( ) return self as result, member function is_valid return boolean, overriding member function do_execute(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base) return boolean, - overriding member procedure calc_execution_result(self in out nocopy ut_test) + overriding member procedure calc_execution_result(self in out nocopy ut_test), + overriding member procedure fail(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) ) / diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index d33842004..6049b5657 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -274,6 +274,7 @@ create or replace package body ut_suite_manager is ,t.object_name from all_objects t where t.owner = a_owner_name + and t.status = 'VALID' -- scan only valid specifications and t.object_type in ('PACKAGE')) loop -- parse the source of the package l_suite := config_package(rec.owner, rec.object_name); From ff26e361240a68c9c492671d61cf6a6417820ce2 Mon Sep 17 00:00:00 2001 From: Pazus Date: Wed, 8 Feb 2017 22:02:58 +0300 Subject: [PATCH 04/16] made buffer clear autonomous --- source/core/ut_output_buffer.pkb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/core/ut_output_buffer.pkb b/source/core/ut_output_buffer.pkb index 6283348a9..1a9451734 100644 --- a/source/core/ut_output_buffer.pkb +++ b/source/core/ut_output_buffer.pkb @@ -111,9 +111,11 @@ create or replace package body ut_output_buffer is procedure cleanup_buffer(a_retention_time_sec naturaln := gc_buffer_retention_sec) is l_retention_days number := a_retention_time_sec / (60 * 60 * 24); l_max_retention_date date := sysdate - l_retention_days; + pragma autonomous_transaction; -- the cleanup should initiate transaction begin delete from ut_output_buffer_tmp t where t.start_date <= l_max_retention_date; + commit; end; end; From 9caa87040e0371ee1eb9d7c79facad039c26f146 Mon Sep 17 00:00:00 2001 From: Pazus Date: Fri, 17 Feb 2017 09:19:01 +0300 Subject: [PATCH 05/16] introduced warning concept --- source/core/types/ut_event_listener.tpb | 7 +++++++ source/core/types/ut_event_listener.tps | 3 ++- source/core/types/ut_event_listener_base.tps | 5 +++-- source/core/types/ut_reporter_base.tpb | 7 +++++++ source/core/types/ut_reporter_base.tps | 5 ++++- source/core/types/ut_suite.tpb | 5 +++-- source/core/types/ut_test.tpb | 10 +++++----- source/reporters/ut_documentation_reporter.tpb | 16 +++++++++++++++- 8 files changed, 46 insertions(+), 12 deletions(-) diff --git a/source/core/types/ut_event_listener.tpb b/source/core/types/ut_event_listener.tpb index 102f811c2..52f040a8a 100644 --- a/source/core/types/ut_event_listener.tpb +++ b/source/core/types/ut_event_listener.tpb @@ -88,6 +88,13 @@ create or replace type body ut_event_listener is end if; end loop; + end fire_event; + + overriding member procedure save_warning(self in out nocopy ut_event_listener, a_item ut_suite_item_base, a_message varchar2) is + begin + for i in 1..self.reporters.count loop + self.reporters(i).save_warning(a_item, a_message); + end loop; end; end; diff --git a/source/core/types/ut_event_listener.tps b/source/core/types/ut_event_listener.tps index 9f122d396..00e9914e6 100644 --- a/source/core/types/ut_event_listener.tps +++ b/source/core/types/ut_event_listener.tps @@ -19,6 +19,7 @@ create or replace type ut_event_listener under ut_event_listener_base( constructor function ut_event_listener(self in out nocopy ut_event_listener, a_reporters ut_reporters) return self as result, overriding member procedure fire_before_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), overriding member procedure fire_after_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), - overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) + overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), + overriding member procedure save_warning(self in out nocopy ut_event_listener, a_item ut_suite_item_base, a_message varchar2) ) / diff --git a/source/core/types/ut_event_listener_base.tps b/source/core/types/ut_event_listener_base.tps index 3873ada17..0aa185c1c 100644 --- a/source/core/types/ut_event_listener_base.tps +++ b/source/core/types/ut_event_listener_base.tps @@ -1,4 +1,4 @@ -create or replace type ut_event_listener_base as object( +create or replace type ut_event_listener_base as object( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -18,6 +18,7 @@ create or replace type ut_event_listener_base as object( name varchar2(250), member procedure fire_before_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), member procedure fire_after_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), - member procedure fire_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) + member procedure fire_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), + member procedure save_warning(self in out nocopy ut_event_listener_base,a_item ut_suite_item_base, a_message varchar2) ) not final not instantiable / diff --git a/source/core/types/ut_reporter_base.tpb b/source/core/types/ut_reporter_base.tpb index 74025dad4..5a44e3744 100644 --- a/source/core/types/ut_reporter_base.tpb +++ b/source/core/types/ut_reporter_base.tpb @@ -21,6 +21,7 @@ create or replace type body ut_reporter_base is self.self_type := a_self_type; self.reporter_id := sys_guid(); self.start_date := sysdate(); + self.warnings := ut_varchar2_list(); return; end; @@ -131,5 +132,11 @@ create or replace type body ut_reporter_base is begin ut_output_buffer.close(self); end; + + member procedure save_warning(self in out nocopy ut_reporter_base, a_item ut_suite_item_base, a_message varchar2) is + begin + self.warnings.extend; + self.warnings(self.warnings.last) := a_message; + end; end; / diff --git a/source/core/types/ut_reporter_base.tps b/source/core/types/ut_reporter_base.tps index e618c2a5e..1980e6d79 100644 --- a/source/core/types/ut_reporter_base.tps +++ b/source/core/types/ut_reporter_base.tps @@ -18,6 +18,7 @@ create or replace type ut_reporter_base force authid current_user as object( self_type varchar2(250), reporter_id raw(32), start_date date, + warnings ut_varchar2_list, final member procedure init(self in out nocopy ut_reporter_base, a_self_type varchar2), final member function get_reporter_id(self in out nocopy ut_reporter_base) return raw, @@ -59,7 +60,9 @@ create or replace type ut_reporter_base force authid current_user as object( member procedure after_calling_suite(self in out nocopy ut_reporter_base, a_suite in ut_logical_suite), -- run hooks continued - member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run) + member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run), + + member procedure save_warning(self in out nocopy ut_reporter_base, a_item ut_suite_item_base, a_message varchar2) ) not final not instantiable diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index c282f4bcb..16bf439cc 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -95,7 +95,8 @@ create or replace type body ut_suite as l_completed_without_errors := self.after_each.do_execute(self, a_listener); if not l_completed_without_errors then - self.items(i).fail(a_listener, 'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); + a_listener.save_warning(self,'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); + --self.items(i).fail(a_listener, 'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); end if; else @@ -110,7 +111,7 @@ create or replace type body ut_suite as l_suite_step_without_errors := self.after_all.do_execute(self, a_listener); if not l_suite_step_without_errors then - do_fail('Afterall procedure failed: '||chr(10)); + a_listener.save_warning(self, 'Afterall procedure failed: '||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); end if; else do_fail('Beforeall procedure failed: '||chr(10)); diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index e8d1717d4..51b67bdcd 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -63,11 +63,11 @@ create or replace type body ut_test as l_completed_without_errors := self.before_test.do_execute(self, a_listener); if l_completed_without_errors then - l_completed_without_errors := self.item.do_execute(self, a_listener); - end if; - - if l_completed_without_errors then - l_completed_without_errors := self.after_test.do_execute(self, a_listener); + -- execute the test + self.item.do_execute(self, a_listener); + + -- perform cleanup regardless of the test failure + self.after_test.do_execute(self, a_listener); end if; self.rollback_to_savepoint(l_savepoint); diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index a14545bf6..eb7ec3dc1 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -116,15 +116,29 @@ create or replace type body ut_documentation_reporter is end loop; end if; end; + + procedure print_warnings is + begin + if self.warnings is not null and self.warnings.count>0 then + self.print_text( 'Warnings:' ); + self.print_text( ' ' ); + for i in 1 .. self.warnings.count loop + self.print_text(self.warnings(i)); + self.print_text(' '); + end loop; + end if; + end; begin print_failures_details(a_run); + print_warnings(); self.print_text( 'Finished in '||a_run.execution_time||' seconds' ); l_summary_text := a_run.results_count.total_count || ' tests, ' ||a_run.results_count.failure_count||' failed, ' ||a_run.results_count.errored_count||' errored, ' - ||a_run.results_count.ignored_count||' ignored'; + ||a_run.results_count.ignored_count||' ignored.'|| + case when self.warnings.count>0 then ' '||self.warnings.count||' warning(s)' end; if a_run.results_count.failure_count > 0 then self.print_red_text(l_summary_text); else From 84d6dd425030f86db2cfe0cd6421987ffdab6d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20G=C4=99bal?= Date: Wed, 22 Feb 2017 21:35:27 +0000 Subject: [PATCH 06/16] Changed logic, where the after_test was not executed if before_test has failed. Now the after_test gets executed regardless of before_test status --- source/core/types/ut_test.tpb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index 51b67bdcd..d8b995003 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -65,10 +65,10 @@ create or replace type body ut_test as if l_completed_without_errors then -- execute the test self.item.do_execute(self, a_listener); - - -- perform cleanup regardless of the test failure - self.after_test.do_execute(self, a_listener); + end if; + -- perform cleanup regardless of the test or setup failure + self.after_test.do_execute(self, a_listener); self.rollback_to_savepoint(l_savepoint); @@ -87,7 +87,7 @@ create or replace type body ut_test as self.results := ut_assert_processor.get_asserts_results(); self.results_count := ut_results_counter(self.result); end; - + overriding member procedure fail(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) is begin ut_utils.debug_log('ut_test.fail'); @@ -98,7 +98,7 @@ create or replace type body ut_test as self.end_time := self.start_time; a_listener.fire_after_event(ut_utils.gc_test, self); end; - + end; / From fa52a091c52c5a84376739e8aa6790e6d295faa7 Mon Sep 17 00:00:00 2001 From: Pazus Date: Thu, 23 Feb 2017 11:08:07 +0300 Subject: [PATCH 07/16] refactored --- .../test_remove_rooms_by_name.pkg | 32 +++++++++++++++++++ source/core/types/ut_event_listener.tpb | 7 ---- source/core/types/ut_event_listener.tps | 3 +- source/core/types/ut_event_listener_base.tps | 5 ++- source/core/types/ut_reporter_base.tpb | 8 +---- source/core/types/ut_reporter_base.tps | 7 ++-- source/core/types/ut_results_counter.tpb | 16 +++++++--- source/core/types/ut_results_counter.tps | 2 ++ source/core/types/ut_suite.tpb | 23 ++++++------- source/core/types/ut_suite_item.tpb | 8 +++++ source/core/types/ut_suite_item.tps | 5 +-- source/core/types/ut_suite_item_base.tps | 3 +- source/core/types/ut_test.tpb | 6 ++-- .../reporters/ut_documentation_reporter.tpb | 29 ++++++++++++++--- 14 files changed, 102 insertions(+), 52 deletions(-) diff --git a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg index 8a8a66d92..01c21841a 100644 --- a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg +++ b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg @@ -5,11 +5,26 @@ create or replace package test_remove_rooms_by_name as -- %beforeall procedure setup_rooms; + + -- %beforeeach + procedure setup_the_room; + + -- %aftereach + procedure clean_the_room; + + -- %afterall + procedure clean_rooms; -- %test -- %displayname(Removes a room without content in it) procedure remove_empty_room; + -- %beforetest(remove_empty_room) + procedure setup_test_room; + + -- %aftertest(remove_empty_room) + procedure clean_test_room; + -- %test -- %displayname(Does not remove room when it has content) procedure room_with_content; @@ -24,6 +39,7 @@ create or replace package body test_remove_rooms_by_name as procedure setup_rooms is begin + insert all into rooms values(1, 'Dining Room') into rooms values(2, 'Living Room') @@ -44,6 +60,22 @@ create or replace package body test_remove_rooms_by_name as into room_contents values(9, 3, 'Whiteboard') select 1 from dual; end; + + -- %beforeeach + procedure setup_the_room is begin null end; + + -- %aftereach + procedure clean_the_room is begin null end; + + -- %afterall + procedure clean_rooms is begin null end; + + -- %beforetest(remove_empty_room) + procedure setup_test_room is begin null end; + + -- %aftertest(remove_empty_room) + procedure clean_test_room is begin null end; + procedure remove_empty_room is l_rooms_not_named_b sys_refcursor; diff --git a/source/core/types/ut_event_listener.tpb b/source/core/types/ut_event_listener.tpb index 52f040a8a..3d29f567d 100644 --- a/source/core/types/ut_event_listener.tpb +++ b/source/core/types/ut_event_listener.tpb @@ -89,13 +89,6 @@ create or replace type body ut_event_listener is end loop; end fire_event; - - overriding member procedure save_warning(self in out nocopy ut_event_listener, a_item ut_suite_item_base, a_message varchar2) is - begin - for i in 1..self.reporters.count loop - self.reporters(i).save_warning(a_item, a_message); - end loop; - end; end; / diff --git a/source/core/types/ut_event_listener.tps b/source/core/types/ut_event_listener.tps index 00e9914e6..9f122d396 100644 --- a/source/core/types/ut_event_listener.tps +++ b/source/core/types/ut_event_listener.tps @@ -19,7 +19,6 @@ create or replace type ut_event_listener under ut_event_listener_base( constructor function ut_event_listener(self in out nocopy ut_event_listener, a_reporters ut_reporters) return self as result, overriding member procedure fire_before_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), overriding member procedure fire_after_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), - overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), - overriding member procedure save_warning(self in out nocopy ut_event_listener, a_item ut_suite_item_base, a_message varchar2) + overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) ) / diff --git a/source/core/types/ut_event_listener_base.tps b/source/core/types/ut_event_listener_base.tps index 0aa185c1c..3873ada17 100644 --- a/source/core/types/ut_event_listener_base.tps +++ b/source/core/types/ut_event_listener_base.tps @@ -1,4 +1,4 @@ -create or replace type ut_event_listener_base as object( +create or replace type ut_event_listener_base as object( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -18,7 +18,6 @@ create or replace type ut_event_listener_base as object( name varchar2(250), member procedure fire_before_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), member procedure fire_after_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), - member procedure fire_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), - member procedure save_warning(self in out nocopy ut_event_listener_base,a_item ut_suite_item_base, a_message varchar2) + member procedure fire_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) ) not final not instantiable / diff --git a/source/core/types/ut_reporter_base.tpb b/source/core/types/ut_reporter_base.tpb index 5a44e3744..1db563d27 100644 --- a/source/core/types/ut_reporter_base.tpb +++ b/source/core/types/ut_reporter_base.tpb @@ -21,7 +21,6 @@ create or replace type body ut_reporter_base is self.self_type := a_self_type; self.reporter_id := sys_guid(); self.start_date := sysdate(); - self.warnings := ut_varchar2_list(); return; end; @@ -132,11 +131,6 @@ create or replace type body ut_reporter_base is begin ut_output_buffer.close(self); end; - - member procedure save_warning(self in out nocopy ut_reporter_base, a_item ut_suite_item_base, a_message varchar2) is - begin - self.warnings.extend; - self.warnings(self.warnings.last) := a_message; - end; + end; / diff --git a/source/core/types/ut_reporter_base.tps b/source/core/types/ut_reporter_base.tps index 1980e6d79..d21a991f7 100644 --- a/source/core/types/ut_reporter_base.tps +++ b/source/core/types/ut_reporter_base.tps @@ -1,4 +1,4 @@ -create or replace type ut_reporter_base force authid current_user as object( +create or replace type ut_reporter_base authid current_user as object( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -18,7 +18,6 @@ create or replace type ut_reporter_base force authid current_user as object( self_type varchar2(250), reporter_id raw(32), start_date date, - warnings ut_varchar2_list, final member procedure init(self in out nocopy ut_reporter_base, a_self_type varchar2), final member function get_reporter_id(self in out nocopy ut_reporter_base) return raw, @@ -60,9 +59,7 @@ create or replace type ut_reporter_base force authid current_user as object( member procedure after_calling_suite(self in out nocopy ut_reporter_base, a_suite in ut_logical_suite), -- run hooks continued - member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run), - - member procedure save_warning(self in out nocopy ut_reporter_base, a_item ut_suite_item_base, a_message varchar2) + member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run) ) not final not instantiable diff --git a/source/core/types/ut_results_counter.tpb b/source/core/types/ut_results_counter.tpb index d504307a6..5c0daba51 100644 --- a/source/core/types/ut_results_counter.tpb +++ b/source/core/types/ut_results_counter.tpb @@ -17,10 +17,11 @@ create or replace type body ut_results_counter as */ constructor function ut_results_counter(self in out nocopy ut_results_counter) return self as result is begin - self.ignored_count := 0; - self.success_count := 0; - self.failure_count := 0; - self.errored_count := 0; + self.ignored_count := 0; + self.success_count := 0; + self.failure_count := 0; + self.errored_count := 0; + self.warnings_count := 0; return; end; @@ -39,10 +40,17 @@ create or replace type body ut_results_counter as self.success_count := self.success_count + a_item.success_count; self.failure_count := self.failure_count + a_item.failure_count; self.errored_count := self.errored_count + a_item.errored_count; + self.warnings_count := self.warnings_count + a_item.warnings_count; + end; + + member procedure increase_warning_count(self in out nocopy ut_results_counter) is + begin + self.warnings_count := self.warnings_count + 1; end; member function total_count return integer is begin + --skip warnings here return self.ignored_count + self.success_count + self.failure_count + self.errored_count; end; diff --git a/source/core/types/ut_results_counter.tps b/source/core/types/ut_results_counter.tps index 6f14b278f..7d4e7a7f2 100644 --- a/source/core/types/ut_results_counter.tps +++ b/source/core/types/ut_results_counter.tps @@ -19,9 +19,11 @@ create or replace type ut_results_counter as object( success_count integer, failure_count integer, errored_count integer, + warnings_count integer, constructor function ut_results_counter(self in out nocopy ut_results_counter) return self as result, constructor function ut_results_counter(self in out nocopy ut_results_counter, a_status integer) return self as result, member procedure sum_counter_values(self in out nocopy ut_results_counter, a_item ut_results_counter), + member procedure increase_warning_count(self in out nocopy ut_results_counter), member function total_count return integer, member function result_status return integer ) diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 16bf439cc..8980f55aa 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -81,6 +81,7 @@ create or replace type body ut_suite as --savepoint l_item_savepoint := self.items(i).create_savepoint_if_needed(); + --before each --includes listener calls for before and after actions l_completed_without_errors := self.before_each.do_execute(self, a_listener); @@ -88,30 +89,26 @@ create or replace type body ut_suite as -- execute the item (test or suite) if l_completed_without_errors then l_completed_without_errors := self.items(i).do_execute(a_listener); - - --after each - --includes listener calls for before and after actions - -- run afteeach even if a test raised an exception - l_completed_without_errors := self.after_each.do_execute(self, a_listener); - - if not l_completed_without_errors then - a_listener.save_warning(self,'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); - --self.items(i).fail(a_listener, 'Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); - end if; - else self.items(i).fail(a_listener, 'Beforeach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); end if; + + --after each + --includes listener calls for before and after actions + --run afteeach even if a test raised an exception + l_completed_without_errors := self.after_each.do_execute(self, a_listener); + if not l_completed_without_errors then + self.put_warning('Aftereach procedure failed:'||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); + end if; --rollback to savepoint self.items(i).rollback_to_savepoint(l_item_savepoint); - -- exit when not l_completed_without_errors; end loop; l_suite_step_without_errors := self.after_all.do_execute(self, a_listener); if not l_suite_step_without_errors then - a_listener.save_warning(self, 'Afterall procedure failed: '||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); + self.put_warning('Afterall procedure failed: '||chr(10)||ut_assert_processor.get_asserts_results()(1).error_message); end if; else do_fail('Beforeall procedure failed: '||chr(10)); diff --git a/source/core/types/ut_suite_item.tpb b/source/core/types/ut_suite_item.tpb index 1ad1d4fbe..394f64983 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -29,6 +29,7 @@ create or replace type body ut_suite_item as self.rollback_type := a_rollback_type; self.ignore_flag := ut_utils.boolean_to_int(a_ignore_flag); self.results_count := ut_results_counter(); + self.warnings := ut_varchar2_list(); end; member procedure set_ignore_flag(self in out nocopy ut_suite_item, a_ignore_flag boolean) is @@ -73,6 +74,13 @@ create or replace type body ut_suite_item as begin return ut_utils.time_diff(start_time, end_time); end; + + member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2) is + begin + self.warnings.extend; + self.warnings(self.warnings.last) := a_message; + self.results_count.increase_warning_count; + end; end; / diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 3831d3eeb..9d58e2336 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -1,4 +1,4 @@ -create or replace type ut_suite_item under ut_suite_item_base ( +create or replace type ut_suite_item force under ut_suite_item_base ( /* utPLSQL - Version X.X.X.X Copyright 2016 - 2017 utPLSQL Project @@ -29,7 +29,8 @@ create or replace type ut_suite_item under ut_suite_item_base ( not instantiable member function do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) return boolean, final member procedure do_execute(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base), not instantiable member procedure calc_execution_result(self in out nocopy ut_suite_item), - not instantiable member procedure fail(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) + not instantiable member procedure fail(self in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2), + member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2) ) not final not instantiable diff --git a/source/core/types/ut_suite_item_base.tps b/source/core/types/ut_suite_item_base.tps index f4657eff0..bff144dec 100644 --- a/source/core/types/ut_suite_item_base.tps +++ b/source/core/types/ut_suite_item_base.tps @@ -53,7 +53,8 @@ create or replace type ut_suite_item_base authid current_user as object ( --execution result fields start_time timestamp with time zone, end_time timestamp with time zone, - result integer(1) + result integer(1), + warnings ut_varchar2_list ) not final not instantiable diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index 51b67bdcd..bf5f70785 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -65,10 +65,10 @@ create or replace type body ut_test as if l_completed_without_errors then -- execute the test self.item.do_execute(self, a_listener); - - -- perform cleanup regardless of the test failure - self.after_test.do_execute(self, a_listener); end if; + + -- perform cleanup regardless of the test failure + self.after_test.do_execute(self, a_listener); self.rollback_to_savepoint(l_savepoint); diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index eb7ec3dc1..77f2ff734 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -67,6 +67,7 @@ create or replace type body ut_documentation_reporter is overriding member procedure after_calling_run(self in out nocopy ut_documentation_reporter, a_run in ut_run) as l_summary_text varchar2(4000); + l_warnings ut_varchar2_list := ut_varchar2_list(); procedure print_failure_for_assert(a_assert ut_assert_result) is l_lines ut_varchar2_list; begin @@ -117,13 +118,31 @@ create or replace type body ut_documentation_reporter is end if; end; - procedure print_warnings is + procedure print_warnings is + procedure gather_warnings(a_item ut_suite_item) is + l_suite ut_logical_suite; + begin + --process warnings of child items first + if a_item is of(ut_logical_suite) then + l_suite := treat(a_item as ut_logical_suite); + for item_ind in 1..l_suite.items.count loop + gather_warnings(l_suite.items(item_ind)); + end loop; + end if; + + --then process self warnings + for warn_ind in 1..a_item.warnings.count loop + l_warnings.extend; + l_warnings(l_warnings.last) := a_item.warnings(warn_ind); + end loop; + end; begin - if self.warnings is not null and self.warnings.count>0 then + + if l_warnings.count>0 then self.print_text( 'Warnings:' ); self.print_text( ' ' ); - for i in 1 .. self.warnings.count loop - self.print_text(self.warnings(i)); + for i in 1 .. l_warnings.count loop + self.print_text(l_warnings(i)); self.print_text(' '); end loop; end if; @@ -138,7 +157,7 @@ create or replace type body ut_documentation_reporter is ||a_run.results_count.failure_count||' failed, ' ||a_run.results_count.errored_count||' errored, ' ||a_run.results_count.ignored_count||' ignored.'|| - case when self.warnings.count>0 then ' '||self.warnings.count||' warning(s)' end; + case when l_warnings.count>0 then ' '||l_warnings.count||' warning(s)' end; if a_run.results_count.failure_count > 0 then self.print_red_text(l_summary_text); else From 7fa55d0e84b77d28cf867bfb3bebae205f5cdf93 Mon Sep 17 00:00:00 2001 From: Pazus Date: Thu, 23 Feb 2017 12:06:02 +0300 Subject: [PATCH 08/16] refactor reporting --- .../test_remove_rooms_by_name.pkg | 19 ++++++++++-------- .../reporters/ut_documentation_reporter.tpb | 20 +++++++++++++------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg index 01c21841a..e7a90d672 100644 --- a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg +++ b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg @@ -17,12 +17,12 @@ create or replace package test_remove_rooms_by_name as -- %test -- %displayname(Removes a room without content in it) - procedure remove_empty_room; - -- %beforetest(remove_empty_room) + -- %aftertest(remove_empty_room) + procedure remove_empty_room; + procedure setup_test_room; - -- %aftertest(remove_empty_room) procedure clean_test_room; -- %test @@ -62,25 +62,28 @@ create or replace package body test_remove_rooms_by_name as end; -- %beforeeach - procedure setup_the_room is begin null end; + procedure setup_the_room is begin null; end; -- %aftereach - procedure clean_the_room is begin null end; + procedure clean_the_room is begin null; end; -- %afterall - procedure clean_rooms is begin null end; + procedure clean_rooms is begin null; + end; -- %beforetest(remove_empty_room) - procedure setup_test_room is begin null end; + procedure setup_test_room is begin null; + raise_application_error(-20001,'Test exception'); end; -- %aftertest(remove_empty_room) - procedure clean_test_room is begin null end; + procedure clean_test_room is begin null; end; procedure remove_empty_room is l_rooms_not_named_b sys_refcursor; l_remaining_rooms sys_refcursor; begin + open l_rooms_not_named_b for select * from rooms where name not like 'B%'; remove_rooms_by_name('B%'); diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index 77f2ff734..a5558fe81 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -118,7 +118,7 @@ create or replace type body ut_documentation_reporter is end if; end; - procedure print_warnings is + procedure print_warnings(a_run in ut_run) is procedure gather_warnings(a_item ut_suite_item) is l_suite ut_logical_suite; begin @@ -131,12 +131,20 @@ create or replace type body ut_documentation_reporter is end if; --then process self warnings - for warn_ind in 1..a_item.warnings.count loop - l_warnings.extend; - l_warnings(l_warnings.last) := a_item.warnings(warn_ind); - end loop; + if a_item.warnings is not null and a_item.warnings.count > 0 then + for warn_ind in 1..a_item.warnings.count loop + l_warnings.extend; + l_warnings(l_warnings.last) := ' '||l_warnings.last||') '||a_item.path||': '|| + regexp_replace(a_item.warnings(warn_ind),'('||chr(10)||'|'||chr(13)||')','\1 '); + end loop; + end if; end; begin + if a_run.items is not null and a_run.items.count >0 then + for run_item in 1..a_run.items.count loop + gather_warnings(a_run.items(run_item)); + end loop; + end if; if l_warnings.count>0 then self.print_text( 'Warnings:' ); @@ -150,7 +158,7 @@ create or replace type body ut_documentation_reporter is begin print_failures_details(a_run); - print_warnings(); + print_warnings(a_run); self.print_text( 'Finished in '||a_run.execution_time||' seconds' ); l_summary_text := a_run.results_count.total_count || ' tests, ' From 2c9835b8b8bb6cb191604a497ad506d4683eb1d2 Mon Sep 17 00:00:00 2001 From: Pazus Date: Thu, 23 Feb 2017 12:06:32 +0300 Subject: [PATCH 09/16] reverted test staff --- .../test_remove_rooms_by_name.pkg | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg index e7a90d672..8a8a66d92 100644 --- a/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg +++ b/examples/remove_rooms_by_name/test_remove_rooms_by_name.pkg @@ -5,25 +5,10 @@ create or replace package test_remove_rooms_by_name as -- %beforeall procedure setup_rooms; - - -- %beforeeach - procedure setup_the_room; - - -- %aftereach - procedure clean_the_room; - - -- %afterall - procedure clean_rooms; -- %test -- %displayname(Removes a room without content in it) - -- %beforetest(remove_empty_room) - -- %aftertest(remove_empty_room) procedure remove_empty_room; - - procedure setup_test_room; - - procedure clean_test_room; -- %test -- %displayname(Does not remove room when it has content) @@ -39,7 +24,6 @@ create or replace package body test_remove_rooms_by_name as procedure setup_rooms is begin - insert all into rooms values(1, 'Dining Room') into rooms values(2, 'Living Room') @@ -60,30 +44,11 @@ create or replace package body test_remove_rooms_by_name as into room_contents values(9, 3, 'Whiteboard') select 1 from dual; end; - - -- %beforeeach - procedure setup_the_room is begin null; end; - - -- %aftereach - procedure clean_the_room is begin null; end; - - -- %afterall - procedure clean_rooms is begin null; - end; - - -- %beforetest(remove_empty_room) - procedure setup_test_room is begin null; - raise_application_error(-20001,'Test exception'); end; - - -- %aftertest(remove_empty_room) - procedure clean_test_room is begin null; end; - procedure remove_empty_room is l_rooms_not_named_b sys_refcursor; l_remaining_rooms sys_refcursor; begin - open l_rooms_not_named_b for select * from rooms where name not like 'B%'; remove_rooms_by_name('B%'); From 26273ad4c5f6e7923165831139e30973a7beed34 Mon Sep 17 00:00:00 2001 From: Pazus Date: Thu, 23 Feb 2017 12:10:36 +0300 Subject: [PATCH 10/16] last minute change --- source/reporters/ut_documentation_reporter.tpb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index a5558fe81..e99ccaf09 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -134,7 +134,7 @@ create or replace type body ut_documentation_reporter is if a_item.warnings is not null and a_item.warnings.count > 0 then for warn_ind in 1..a_item.warnings.count loop l_warnings.extend; - l_warnings(l_warnings.last) := ' '||l_warnings.last||') '||a_item.path||': '|| + l_warnings(l_warnings.last) := ' '||l_warnings.last||') '||a_item.path||' - '|| regexp_replace(a_item.warnings(warn_ind),'('||chr(10)||'|'||chr(13)||')','\1 '); end loop; end if; From 4d2789ce53935a243e459843d3730f6c9dcae9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20G=C4=99bal?= Date: Thu, 23 Feb 2017 23:44:12 +0000 Subject: [PATCH 11/16] Added tests for behavior when execution invalid objects or unit test code that is raising exceptions in different blocks. Changed error message raised when suite is not found to be more adequate to the reasons for the error. --- source/core/ut_suite_manager.pkb | 2 +- tests/RunAll.sql | 9 ++++ ...ntFindTheSuiteWhenPackageSpecIsInvalid.sql | 42 ++++++++++++++++ ...st_suite.ErrorsATestWhenAfterTestFails.sql | 46 ++++++++++++++++++ ...t_suite.ErrorsATestWhenBeforeTestFails.sql | 46 ++++++++++++++++++ ...suite.ErrorsEachTestWhenBeforeAllFails.sql | 47 ++++++++++++++++++ ...uite.ErrorsEachTestWhenBeforeEachFails.sql | 48 +++++++++++++++++++ ...rrorsEachTestWhenPackageHasInvalidBody.sql | 43 +++++++++++++++++ ...ite.ErrorsEachTestWhenPackageHasNoBody.sql | 36 ++++++++++++++ ....ReportsWarningsATestWhenAfterAllFails.sql | 46 ++++++++++++++++++ ...ReportsWarningsATestWhenAfterEachFails.sql | 46 ++++++++++++++++++ 11 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 tests/ut_suite_manager/ut_suite_manager.DoesntFindTheSuiteWhenPackageSpecIsInvalid.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsATestWhenAfterTestFails.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsATestWhenBeforeTestFails.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeAllFails.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeEachFails.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasInvalidBody.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasNoBody.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterAllFails.sql create mode 100644 tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterEachFails.sql diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 6049b5657..7255df210 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -509,7 +509,7 @@ create or replace package body ut_suite_manager is l_suite := l_schema_suites(l_root_suite_name); exception when no_data_found then - raise_application_error(-20203, 'Suite ' || l_root_suite_name || ' not found'); + raise_application_error(-20203, 'Suite ' || l_root_suite_name || ' does not exist or is invalid'); end; skip_by_path(l_suite, regexp_substr(l_suite_path, '\.(.+)', subexpression => 1)); diff --git a/tests/RunAll.sql b/tests/RunAll.sql index b6a5ce1b2..852693b1a 100644 --- a/tests/RunAll.sql +++ b/tests/RunAll.sql @@ -124,6 +124,7 @@ create table ut$test_table (val varchar2(1)); @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.configure_execution_by_path.PrepareRunnerForTheTopPackageProcedureByPathCurUser.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.configure_execution_by_path.PrepareRunnerForTheTop2PackageProcedureByPath.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.configure_execution_by_path.PrepareRunnerForTheTop2PackageProcedureByPathCurUser.sql +@@lib/RunTest.sql ut_suite_manager/ut_suite_manager.DoesntFindTheSuiteWhenPackageSpecIsInvalid.sql @@lib/RunTest.sql ut_test/ut_test.IgnoreFlagSkipTest.sql @@lib/RunTest.sql ut_test/ut_test.OwnerNameInvalid.sql @@ -145,7 +146,15 @@ create table ut$test_table (val varchar2(1)); @@lib/RunTest.sql ut_test/ut_test.TeardownProcedureNameNull.sql @@lib/RunTest.sql ut_test/ut_test.IgnoreTollbackToSavepointException.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsATestWhenAfterTestFails.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsATestWhenBeforeTestFails.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeAllFails.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeEachFails.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasInvalidBody.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasNoBody.sql @@lib/RunTest.sql ut_test_suite/ut_test_suite.IgnoreFlagSkipSuite.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterAllFails.sql +@@lib/RunTest.sql ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterEachFails.sql @@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.Auto.sql @@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.AutoOnFailure.sql @@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.Manual.sql diff --git a/tests/ut_suite_manager/ut_suite_manager.DoesntFindTheSuiteWhenPackageSpecIsInvalid.sql b/tests/ut_suite_manager/ut_suite_manager.DoesntFindTheSuiteWhenPackageSpecIsInvalid.sql new file mode 100644 index 000000000..4afe338b7 --- /dev/null +++ b/tests/ut_suite_manager/ut_suite_manager.DoesntFindTheSuiteWhenPackageSpecIsInvalid.sql @@ -0,0 +1,42 @@ +set termout off +create or replace package failing_invalid_spec as + --%suite + gv_glob_val non_existing_table.id%type := 0; + + --%beforeall + procedure before_all; + --%test + procedure test1; + --%test + procedure test2; +end; +/ +create or replace package body failing_invalid_spec as + procedure before_all is begin gv_glob_val := 1; end; + procedure test1 is begin ut.expect(1).to_equal(1); end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end; +/ +set termout on + +declare + l_objects_to_run ut_suite_items; +begin + begin + --act + l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('failing_invalid_spec')); + exception + when others then + if sqlerrm like '%failing_invalid_spec%' then + :test_result := ut_utils.tr_success; + end if; + end; + + if :test_result != ut_utils.tr_success or :test_result is null then + dbms_output.put_line('Failed: Expected exception with text like ''%failing_invalid_spec%'' but got:'''||sqlerrm||''''); + end if; +end; +/ + +drop package failing_invalid_spec +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenAfterTestFails.sql b/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenAfterTestFails.sql new file mode 100644 index 000000000..a34d92f7c --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenAfterTestFails.sql @@ -0,0 +1,46 @@ +create or replace package failing_after_test as + --%suite + gv_glob_val number := 0; + --%test + --%aftertest(after_test1) + procedure test1; + procedure after_test1; + --%test + procedure test2; +end; +/ +create or replace package body failing_after_test as + procedure test1 is begin gv_glob_val := 1; ut.expect(1).to_equal(2); end; + procedure after_test1 is begin gv_glob_val := 1/0; end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_after_test'); + dbms_output.get_lines( l_output_data, l_num_lines); + if failing_after_test.gv_glob_val = 1 then + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 1 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: test1 was not marked as failed'); + end if; + else + dbms_output.put_line('Failed: test1 was not executed'); + end if; + +end; +/ + +drop package failing_after_test +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenBeforeTestFails.sql b/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenBeforeTestFails.sql new file mode 100644 index 000000000..9cc57b6ec --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsATestWhenBeforeTestFails.sql @@ -0,0 +1,46 @@ +create or replace package failing_before_test as + --%suite + gv_glob_val number := 0; + procedure before_test1; + --%test + --%beforetest(before_test1) + procedure test1; + --%test + procedure test2; +end; +/ +create or replace package body failing_before_test as + procedure before_test1 is begin gv_glob_val := 1/0; end; + procedure test1 is begin gv_glob_val := 1; ut.expect(1).to_equal(2); end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_before_test'); + dbms_output.get_lines( l_output_data, l_num_lines); + if failing_before_test.gv_glob_val = 0 then + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 1 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: test1 was not marked as failed'); + end if; + else + dbms_output.put_line('Failed: test1 was executed even though the beforetest failed'); + end if; + +end; +/ + +drop package failing_before_test +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeAllFails.sql b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeAllFails.sql new file mode 100644 index 000000000..bd365be47 --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeAllFails.sql @@ -0,0 +1,47 @@ +create or replace package failing_before_all as + --%suite + gv_glob_val number := 0; + --%beforeall + procedure before_all; + --%test + procedure test1; + --%test + procedure test2; +end; +/ +create or replace package body failing_before_all as + procedure before_all is begin gv_glob_val := 1/0; end; + procedure test1 is begin gv_glob_val := 1; ut.expect(1).to_equal(2); end; + procedure test2 is begin gv_glob_val := 2; ut.expect(1).to_equal(2); end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_before_all'); + + --assert + if failing_before_all.gv_glob_val = 0 then + dbms_output.get_lines( l_output_data, l_num_lines); + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 2 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; + else + dbms_output.put_line('Failed: tests were executed even though the beforeall failed'); + end if; +end; +/ + +drop package failing_before_all +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeEachFails.sql b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeEachFails.sql new file mode 100644 index 000000000..8f7a4dbfa --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenBeforeEachFails.sql @@ -0,0 +1,48 @@ +create or replace package failing_before_each as + --%suite + gv_glob_val number := 0; + --%beforeeach + procedure before_each; + --%test + procedure test1; + --%test + procedure test2; +end; +/ +create or replace package body failing_before_each as + procedure before_each is begin gv_glob_val := 1/0; end; + procedure test1 is begin ut.expect(1).to_equal(2); end; + procedure test2 is begin ut.expect(1).to_equal(2); end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_before_each'); + + --assert + if failing_before_each.gv_glob_val = 0 then + dbms_output.get_lines( l_output_data, l_num_lines); + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 2 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; + else + dbms_output.put_line('Failed: tests were executed even though the beforeall failed'); + end if; +end; +/ + +drop package failing_before_each +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasInvalidBody.sql b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasInvalidBody.sql new file mode 100644 index 000000000..793b06983 --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasInvalidBody.sql @@ -0,0 +1,43 @@ +create or replace package failing_bad_body as + --%suite + gv_glob_val number := 0; + --%beforeall + procedure before_all; + --%test + procedure test1; + --%test + procedure test2; +end; +/ +set termout off +create or replace package body failing_bad_body as +begin + null; +end; +/ +set termout on + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_bad_body'); + dbms_output.get_lines( l_output_data, l_num_lines); + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 2 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; +end; +/ + +drop package failing_bad_body +/ diff --git a/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasNoBody.sql b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasNoBody.sql new file mode 100644 index 000000000..21ec3dc1e --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ErrorsEachTestWhenPackageHasNoBody.sql @@ -0,0 +1,36 @@ +create or replace package failing_no_body as + --%suite + gv_glob_val number := 0; + --%beforeall + procedure before_all; + --%test + procedure test1; + --%test + procedure test2; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_no_body'); + dbms_output.get_lines( l_output_data, l_num_lines); + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 0 failed, 2 errored%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; +end; +/ + +drop package failing_no_body +/ diff --git a/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterAllFails.sql b/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterAllFails.sql new file mode 100644 index 000000000..cc52c4aae --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterAllFails.sql @@ -0,0 +1,46 @@ +create or replace package failing_after_all as + --%suite + gv_glob_val number := 0; + --%test + procedure test1; + --%test + procedure test2; + --%afterall + procedure after_all; +end; +/ +create or replace package body failing_after_all as + procedure test1 is begin gv_glob_val := gv_glob_val + 1; ut.expect(1).to_equal(2); end; + procedure test2 is begin gv_glob_val := gv_glob_val + 1; ut.expect(1).to_equal(2); end; + procedure after_all is begin gv_glob_val := 1/0; end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_after_all'); + dbms_output.get_lines( l_output_data, l_num_lines); + if failing_after_all.gv_glob_val = 2 then + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 2 failed, 0 errored% 1 warning%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; + else + dbms_output.put_line('Failed: Not all tests were executed'); + end if; + +end; +/ + +drop package failing_after_all +/ diff --git a/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterEachFails.sql b/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterEachFails.sql new file mode 100644 index 000000000..0c92293af --- /dev/null +++ b/tests/ut_test_suite/ut_test_suite.ReportsWarningsATestWhenAfterEachFails.sql @@ -0,0 +1,46 @@ +create or replace package failing_after_each as + --%suite + gv_glob_val number := 0; + --%test + procedure test1; + --%test + procedure test2; + --%aftereach + procedure after_each; +end; +/ +create or replace package body failing_after_each as + procedure test1 is begin gv_glob_val := gv_glob_val + 1; ut.expect(1).to_equal(2); end; + procedure test2 is begin gv_glob_val := gv_glob_val + 1; ut.expect(1).to_equal(2); end; + procedure after_each is begin gv_glob_val := 1/0; end; +end; +/ + +declare + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; +begin + --act + ut.run('failing_after_each'); + dbms_output.get_lines( l_output_data, l_num_lines); + if failing_after_each.gv_glob_val = 2 then + for i in 1 .. l_num_lines loop + if l_output_data(i) like '%2 tests, 2 failed, 0 errored% 2 warning%' then + :test_result := ut_utils.tr_success; + end if; + end loop; + if :test_result != ut_utils.tr_success or :test_result is null then + for i in 1 .. l_num_lines loop + dbms_output.put_line(l_output_data(i)); + end loop; + dbms_output.put_line('Failed: Not all tests were marked as failed'); + end if; + else + dbms_output.put_line('Failed: Not all tests were executed'); + end if; + +end; +/ + +drop package failing_after_each +/ From 1be8914586923a0be7758da08c11269e5522e414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20G=C4=99bal?= Date: Fri, 24 Feb 2017 00:55:19 +0000 Subject: [PATCH 12/16] Added tests for behavior when execution invalid objects or unit test code that is raising exceptions in different blocks. Changed error message raised when suite is not found to be more adequate to the reasons for the error. --- docs/userguide/annotations.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/userguide/annotations.md b/docs/userguide/annotations.md index a0963524c..54ab416aa 100644 --- a/docs/userguide/annotations.md +++ b/docs/userguide/annotations.md @@ -72,9 +72,19 @@ end test_pkg; | `%aftereach` | Procedure | Denotes that the annotated procedure should be executed after each `%test` method in the current suite. | | `%beforetest()` | Procedure | Denotes that mentioned procedure should be executed before the annotated `%test` procedure. | | `%aftertest()` | Procedure | Denotes that mentioned procedure should be executed after the annotated `%test` procedure. | -| `%rollback()` | 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) | +| `%rollback()` | Package/procedure | Configure transaction control behaviour (type). Supported values: `auto`(default) - A savepoint is created before before invocation of each "before block" is and a rollback to specific savepoint is issued after each "after" block; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | | `%disabled` | Package/procedure | Used to disable a suite or a test | +# Using automatic rollbacks in tests +By default, every test is isolated from other tests using savepoint. +This solution is suitable for use-cases, where the code that is getting tested as well as the unit tests themselves do not use transaction control commands (commit/rollback). +In general, your unit tests should not use transaction control as long as the core you are testing is not using it too. +Keeping the transactions uncommitted allows your changes to be isolated and the execution of tests is not impacting others that might be using a shared (integration) development database. + +If however you're in situation, where the code you are testing, is using transaction control (like ETL code is usually doing), then your tests should not use the default rollback(auto) +You should make sure that thr entire suitepath all the way to the root is using manual transaction control in that case. + + # Suitepath concept 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. @@ -148,3 +158,4 @@ A `%suitepath` can be provided in tree ways: * schema - execute all test in the schema * [schema]:suite1[.suite2][.suite3]...[.procedure] - execute all tests in all suites from suite1[.suite2][.suite3]...[.procedure] path. If schema is not provided, then current schema is used. Example: `:all.rooms_tests`. * [schema.]package[.procedure] - execute all tests in the test package provided. The whole hierarchy of suites in the schema is build before, all before/after hooks of partn suites for th provided suite package are executed as well. Example: `tests.test_contact.test_last_name_validator` or simply `test_contact.test_last_name_validator` if `tests` is the current schema. + From c8ead98957b5686a233f3736f470613d4a3f932b Mon Sep 17 00:00:00 2001 From: Pazus Date: Fri, 24 Feb 2017 10:30:54 +0300 Subject: [PATCH 13/16] Update annotations.md --- docs/userguide/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/userguide/annotations.md b/docs/userguide/annotations.md index 54ab416aa..36ad1196e 100644 --- a/docs/userguide/annotations.md +++ b/docs/userguide/annotations.md @@ -72,7 +72,7 @@ end test_pkg; | `%aftereach` | Procedure | Denotes that the annotated procedure should be executed after each `%test` method in the current suite. | | `%beforetest()` | Procedure | Denotes that mentioned procedure should be executed before the annotated `%test` procedure. | | `%aftertest()` | Procedure | Denotes that mentioned procedure should be executed after the annotated `%test` procedure. | -| `%rollback()` | Package/procedure | Configure transaction control behaviour (type). Supported values: `auto`(default) - A savepoint is created before before invocation of each "before block" is and a rollback to specific savepoint is issued after each "after" block; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | +| `%rollback()` | Package/procedure | Configure transaction control behaviour (type). Supported values: `auto`(default) - A savepoint is created before invocation of each "before block" is and a rollback to specific savepoint is issued after each "after" block; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | | `%disabled` | Package/procedure | Used to disable a suite or a test | # Using automatic rollbacks in tests From 4695d629787c349b0460252c33d642f6fd0e0d0d Mon Sep 17 00:00:00 2001 From: Pazus Date: Fri, 24 Feb 2017 10:34:28 +0300 Subject: [PATCH 14/16] Update annotations.md --- docs/userguide/annotations.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/userguide/annotations.md b/docs/userguide/annotations.md index 36ad1196e..1caea7785 100644 --- a/docs/userguide/annotations.md +++ b/docs/userguide/annotations.md @@ -84,6 +84,7 @@ Keeping the transactions uncommitted allows your changes to be isolated and the If however you're in situation, where the code you are testing, is using transaction control (like ETL code is usually doing), then your tests should not use the default rollback(auto) You should make sure that thr entire suitepath all the way to the root is using manual transaction control in that case. +In some cases it is needed to perform DDL in setup/teardown. It is recommended to move such DDL statements to a procedure with pragma autonomous_transaction to eliminate implicit commit of the main session. # Suitepath concept 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. From 96d3d2559e033640b119186ead057ebad54de5e4 Mon Sep 17 00:00:00 2001 From: Pazus Date: Fri, 24 Feb 2017 10:51:04 +0300 Subject: [PATCH 15/16] Create exception-reporting.md --- docs/userguide/exception-reporting.md | 121 ++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 docs/userguide/exception-reporting.md diff --git a/docs/userguide/exception-reporting.md b/docs/userguide/exception-reporting.md new file mode 100644 index 000000000..4df38befa --- /dev/null +++ b/docs/userguide/exception-reporting.md @@ -0,0 +1,121 @@ +# Exception handling and reporting + +The utPLSQL is responsibly for handling exceptions wherever they occure in the test run. Exceptions are pororted as follows: + +* A test package without body faced - each `%test` is reported as failed +* A test package with _invalid body_ - each `%test` is reported as failed +* A test package with _invalid spec_ - *`%test`s are skipped*. Only valid specifications are parsed for annotations. +* A test package that is raising an exception in beforeall - each `%test` is reported as failed +* A test package that is raising an exception in afterall - `%test` are reported normally, warnings are displayed in the summary + +Example: +``` +Remove rooms by name + Removes a room without content in it + Does not remove room when it has content + Raises exception when null room name given + +Warnings: + + 1) test_remove_rooms_by_name - Afterall procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 35 + ORA-06512: at line 6 + +Finished in ,044902 seconds +3 tests, 0 failed, 0 errored, 0 ignored. 1 warning(s) +``` + +* A test package that is raising an exception in `%beforeeach` - each `%test` is reported as failed +* A test package that is raising an exception in `%aftereach` - `%test`s are reported normally, warnings are displayed in the summary + +Example: +``` +Remove rooms by name + Removes a room without content in it + Does not remove room when it has content + Raises exception when null room name given + +Warnings: + + 1) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + + 2) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + + 3) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + +Finished in ,05071 seconds +3 tests, 0 failed, 0 errored, 0 ignored. 3 warning(s) +``` + +* A test package that is raising an exception in test - the `%test` is reported as failed + +Exampple: +``` +Remove rooms by name + Removes a room without content in it (FAILED - 1) + Does not remove room when it has content + Raises exception when null room name given + +Failures: + + 1) remove_empty_room + + error: ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 48 + ORA-06512: at line 6 + +Finished in ,035726 seconds +3 tests, 0 failed, 1 errored, 0 ignored. +``` + +* A test package that is raising an exception in `%beforetest` - the `%test` is reported as failed + +Example: +```` +Remove rooms by name + Removes a room without content in it (FAILED - 1) + Does not remove room when it has content + Raises exception when null room name given + +Failures: + + 1) remove_empty_room + + error: ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 39 + ORA-06512: at line 6 + +Finished in ,039346 seconds +3 tests, 0 failed, 1 errored, 0 ignored. +```` + +* A test package that is raising an exception in `%aftertest` - the `%test` is reported as failed + +Example: +``` +Remove rooms by name + Removes a room without content in it (FAILED - 1) + Does not remove room when it has content + Raises exception when null room name given + +Failures: + + 1) remove_empty_room + + error: ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 42 + ORA-06512: at line 6 + +Finished in ,045523 seconds +3 tests, 0 failed, 1 errored, 0 ignored. +``` From ee89c42d64528a201037896a06378bee22f25c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20G=C4=99bal?= Date: Fri, 24 Feb 2017 09:55:49 +0000 Subject: [PATCH 16/16] Updated exception-reporting. --- docs/userguide/exception-reporting.md | 140 +++++++++++++------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/docs/userguide/exception-reporting.md b/docs/userguide/exception-reporting.md index 4df38befa..6a09b0bef 100644 --- a/docs/userguide/exception-reporting.md +++ b/docs/userguide/exception-reporting.md @@ -1,65 +1,42 @@ # Exception handling and reporting -The utPLSQL is responsibly for handling exceptions wherever they occure in the test run. Exceptions are pororted as follows: +The utPLSQL is responsible for handling exceptions wherever they occur in the test run. utPLSQL is trapping most of the exceptions so that the test execution is not affected by individual tests or test packages throwing an exception. +The framework provides a full stacktrace for every exception that was thrown. The stacktrace is clean and does not include any utPLSQL library calls in it. +To achieve rerunability, the ORA-04068, ORA-04061 exceptions are not handled and test execution will be interrupted if such exception is encountered. This is because of how Oracle behaves on those exceptions. -* A test package without body faced - each `%test` is reported as failed -* A test package with _invalid body_ - each `%test` is reported as failed -* A test package with _invalid spec_ - *`%test`s are skipped*. Only valid specifications are parsed for annotations. -* A test package that is raising an exception in beforeall - each `%test` is reported as failed -* A test package that is raising an exception in afterall - `%test` are reported normally, warnings are displayed in the summary +Test execution can fail for different reasons. The failures on different exceptions are handled as follows: +* A test package without body - each `%test` is reported as failed with exception, nothing is executed +* A test package with _invalid body_ - each `%test` is reported as failed with exception, nothing is executed +* A test package with _invalid spec_ - package is not considered a valid unit test package and is excluded from execution. When trying to run a test package with invalid spec explicitly, exception is raised. Only valid specifications are parsed for annotations +* A test package that is raising an exception in `%beforeall` - each `%test` is reported as failed with exception, `%test`, `%beforeeach`, `%beforetest`, `%aftertest` and `%aftereach` are not executed. `%afterall` is executed to allow cleanup of whatever was done in `%beforeall` +* A test package that is raising an exception in `%beforeeach` - each `%test` is reported as failed with exception, `%test`, `%beforetest` and `%aftertest` is not executed. The `%aftereach` and `%afterall` blocks are getting executed to allow cleanup of whatever was done in `%before...` blocks +* A test package that is raising an exception in `%beforetest` - the `%test` is reported as failed with exception, `%test` is not executed. The `%aftertest`, `%aftereach` and `%afterall` blocks are getting executed to allow cleanup of whatever was done in `%before...` blocks +* A test package that is raising an exception in `%test` - the `%test` is reported as failed with exception. The execution of other blocks continues normally +* A test package that is raising an exception in `%aftertest` - the `%test` is reported as failed with exception. The execution of other blocks continues normally +* A test package that is raising an exception in `%aftereach` - all blocks of the package are executed, as ehe `%aftereach` is a closing block for an individual test. Exception in `%aftereach` is not affecting test results. For every failed execution of `%aftereach` a warning with exception stacktrace is displayed in the summary +* A test package that is raising an exception in `%afterall` - all blocks of the package are executed, as the `%afterall` is the last step of package execution. Exception in `%afterall` is not affecting test results. A warning with exception stacktrace is displayed in the summary -Example: -``` -Remove rooms by name - Removes a room without content in it - Does not remove room when it has content - Raises exception when null room name given - -Warnings: - - 1) test_remove_rooms_by_name - Afterall procedure failed: - ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 35 - ORA-06512: at line 6 - -Finished in ,044902 seconds -3 tests, 0 failed, 0 errored, 0 ignored. 1 warning(s) -``` -* A test package that is raising an exception in `%beforeeach` - each `%test` is reported as failed -* A test package that is raising an exception in `%aftereach` - `%test`s are reported normally, warnings are displayed in the summary - -Example: -``` +Example of reporting with exception thrown in `%beforetest`: +```` Remove rooms by name - Removes a room without content in it + Removes a room without content in it (FAILED - 1) Does not remove room when it has content Raises exception when null room name given -Warnings: - - 1) test_remove_rooms_by_name - Aftereach procedure failed: - ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 - ORA-06512: at line 6 - - 2) test_remove_rooms_by_name - Aftereach procedure failed: - ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 - ORA-06512: at line 6 - - 3) test_remove_rooms_by_name - Aftereach procedure failed: - ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 - ORA-06512: at line 6 +Failures: -Finished in ,05071 seconds -3 tests, 0 failed, 0 errored, 0 ignored. 3 warning(s) -``` - -* A test package that is raising an exception in test - the `%test` is reported as failed + 1) remove_empty_room + + error: ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 39 + ORA-06512: at line 6 + +Finished in ,039346 seconds +3 tests, 0 failed, 1 errored, 0 ignored. +```` -Exampple: +Example of reporting with exception thrown in `%test`: ``` Remove rooms by name Removes a room without content in it (FAILED - 1) @@ -78,10 +55,8 @@ Finished in ,035726 seconds 3 tests, 0 failed, 1 errored, 0 ignored. ``` -* A test package that is raising an exception in `%beforetest` - the `%test` is reported as failed - -Example: -```` +Example of reporting with exception thrown in `%aftertest`: +``` Remove rooms by name Removes a room without content in it (FAILED - 1) Does not remove room when it has content @@ -92,30 +67,55 @@ Failures: 1) remove_empty_room error: ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 39 + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 42 ORA-06512: at line 6 -Finished in ,039346 seconds +Finished in ,045523 seconds 3 tests, 0 failed, 1 errored, 0 ignored. -```` +``` -* A test package that is raising an exception in `%aftertest` - the `%test` is reported as failed +Example of reporting with exception thrown in `%aftereach`: +``` +Remove rooms by name + Removes a room without content in it + Does not remove room when it has content + Raises exception when null room name given + +Warnings: + + 1) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + + 2) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + + 3) test_remove_rooms_by_name - Aftereach procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 31 + ORA-06512: at line 6 + +Finished in ,05071 seconds +3 tests, 0 failed, 0 errored, 0 ignored. 3 warning(s) +``` -Example: +Example of reporting with exception thrown in `%afterall`: ``` Remove rooms by name - Removes a room without content in it (FAILED - 1) + Removes a room without content in it Does not remove room when it has content Raises exception when null room name given -Failures: +Warnings: - 1) remove_empty_room - - error: ORA-20001: Test exception - ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 42 - ORA-06512: at line 6 - -Finished in ,045523 seconds -3 tests, 0 failed, 1 errored, 0 ignored. + 1) test_remove_rooms_by_name - Afterall procedure failed: + ORA-20001: Test exception + ORA-06512: at "UT3.TEST_REMOVE_ROOMS_BY_NAME", line 35 + ORA-06512: at line 6 + +Finished in ,044902 seconds +3 tests, 0 failed, 0 errored, 0 ignored. 1 warning(s) ```