diff --git a/docs/userguide/advanced_data_comparison.md b/docs/userguide/advanced_data_comparison.md index a0f32ce5e..042bb847f 100644 --- a/docs/userguide/advanced_data_comparison.md +++ b/docs/userguide/advanced_data_comparison.md @@ -126,6 +126,85 @@ end; ``` +Example of `include / exclude` for anydata.convertCollection + +```plsql +create or replace type person as object( + name varchar2(100), + age integer +) +/ +create or replace type people as table of person +/ + +create or replace package ut_anydata_inc_exc IS + + --%suite(Anydata) + + --%test(Anydata include) + procedure ut_anydata_test_inc; + + --%test(Anydata exclude) + procedure ut_anydata_test_exc; + + --%test(Fail on age) + procedure ut_fail_anydata_test; + +end ut_anydata_inc_exc; +/ + +create or replace package body ut_anydata_inc_exc IS + + procedure ut_anydata_test_inc IS + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); + begin + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include('NAME'); + end; + + procedure ut_anydata_test_exc IS + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); + begin + --Arrange + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).exclude('AGE'); + end; + + procedure ut_fail_anydata_test IS + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); + begin + --Arrange + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include('AGE'); + end; + +end ut_anydata_inc_exc; +/ + +``` + +will result in : + +```sql +Anydata + Anydata include [.044 sec] + Anydata exclude [.035 sec] + Fail on age [.058 sec] (FAILED - 1) + +Failures: + + 1) ut_fail_anydata_test + Actual: ut3.people [ count = 1 ] was expected to equal: ut3.people [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: 45 + Row No. 1 - Expected: 47 +``` + + + +Example of exclude + Only the columns 'RN', "A_Column" will be compared. Column 'SOME_COL' is excluded. This option can be useful in scenarios where you need to narrow-down the scope of test so that the test is only focused on very specific data. diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index b3f2f0ea6..c50326bbe 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -824,5 +824,30 @@ create or replace package body ut_utils is return l_result; end; + function add_prefix(a_list ut_varchar2_list, a_prefix varchar2, a_connector varchar2 := '/') return ut_varchar2_list is + l_result ut_varchar2_list := ut_varchar2_list(); + l_idx binary_integer; + begin + if a_prefix is not null then + l_idx := a_list.first; + while l_idx is not null loop + l_result.extend; + l_result(l_idx) := add_prefix(a_list(l_idx), a_prefix, a_connector); + l_idx := a_list.next(l_idx); + end loop; + end if; + return l_result; + end; + + function add_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2 is + begin + return a_prefix||a_connector||trim(leading a_connector from a_item); + end; + + function strip_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2 is + begin + return regexp_replace(a_item,a_prefix||a_connector); + end; + end ut_utils; / diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index a075e5458..792bccb52 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -404,5 +404,14 @@ create or replace package ut_utils authid definer is */ function to_cdata(a_clob clob) return clob; + /** + * Add prefix word to elements of list + */ + function add_prefix(a_list ut_varchar2_list, a_prefix varchar2, a_connector varchar2 := '/') return ut_varchar2_list; + + function add_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2; + + function strip_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2; + end ut_utils; / diff --git a/source/expectations/data_values/ut_compound_data_helper.pkb b/source/expectations/data_values/ut_compound_data_helper.pkb index bd259b47d..1d5686f03 100644 --- a/source/expectations/data_values/ut_compound_data_helper.pkb +++ b/source/expectations/data_values/ut_compound_data_helper.pkb @@ -335,6 +335,7 @@ create or replace package body ut_compound_data_helper is l_not_equal_stmt clob; l_where_stmt clob; l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_join_by_list ut_varchar2_list; function get_join_type(a_inclusion_compare in boolean,a_negated in boolean) return varchar2 is begin @@ -356,12 +357,22 @@ create or replace package body ut_compound_data_helper is end; begin + /** + * We already estabilished cursor equality so now we add anydata root if we compare anydata + * to join by. + */ + l_join_by_list := + case + when a_other is of (ut_data_value_anydata) then ut_utils.add_prefix(a_join_by_list, a_other.cursor_details.get_root) + else a_join_by_list + end; + dbms_lob.createtemporary(l_compare_sql, true); --Initiate a SQL template with placeholders ut_utils.append_to_clob(l_compare_sql, g_compare_sql_template); --Generate a pieceso of dynamic SQL that will substitute placeholders gen_sql_pieces_out_of_cursor( - a_other.cursor_details.cursor_columns_info, a_join_by_list, a_unordered, + a_other.cursor_details.cursor_columns_info, l_join_by_list, a_unordered, l_xmltable_stmt, l_select_stmt, l_partition_stmt, l_join_on_stmt, l_not_equal_stmt ); @@ -374,7 +385,7 @@ create or replace package body ut_compound_data_helper is l_compare_sql := replace(l_compare_sql,'{:join_type:}',get_join_type(a_inclusion_type,a_is_negated)); l_compare_sql := replace(l_compare_sql,'{:join_condition:}',l_join_on_stmt); - if l_not_equal_stmt is not null and ((a_join_by_list.count > 0 and not a_is_negated) or (not a_unordered)) then + if l_not_equal_stmt is not null and ((l_join_by_list.count > 0 and not a_is_negated) or (not a_unordered)) then ut_utils.append_to_clob(l_where_stmt,' ( '||l_not_equal_stmt||' ) or '); end if; --If its inclusion we expect a actual set to fully match and have no extra elements over expected diff --git a/source/expectations/data_values/ut_cursor_column.tpb b/source/expectations/data_values/ut_cursor_column.tpb index 3c6931a5d..13b1b3158 100644 --- a/source/expectations/data_values/ut_cursor_column.tpb +++ b/source/expectations/data_values/ut_cursor_column.tpb @@ -26,7 +26,8 @@ create or replace type body ut_cursor_column as self.xml_valid_name else a_access_path||'/'||self.xml_valid_name - end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2 + end; --Access path used for XMLTABLE query + self.filter_path := '/'||self.access_path; --Filter path will differ from access path in anydata type self.transformed_name := case when length(self.xml_valid_name) > 30 then '"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.xml_valid_name)||'"' when self.parent_name is null then diff --git a/source/expectations/data_values/ut_cursor_column.tps b/source/expectations/data_values/ut_cursor_column.tps index db9cbd3ae..93114c431 100644 --- a/source/expectations/data_values/ut_cursor_column.tps +++ b/source/expectations/data_values/ut_cursor_column.tps @@ -1,4 +1,4 @@ -create or replace type ut_cursor_column force authid current_user as object ( +create or replace type ut_cursor_column authid current_user as object ( /* utPLSQL - Version 3 Copyright 2016 - 2018 utPLSQL Project @@ -17,6 +17,7 @@ create or replace type ut_cursor_column force authid current_user as object ( */ parent_name varchar2(4000), access_path varchar2(4000), + filter_path varchar2(4000), display_path varchar2(4000), has_nested_col number(1,0), transformed_name varchar2(2000), diff --git a/source/expectations/data_values/ut_cursor_details.tpb b/source/expectations/data_values/ut_cursor_details.tpb index e6e24eea2..20313ed96 100644 --- a/source/expectations/data_values/ut_cursor_details.tpb +++ b/source/expectations/data_values/ut_cursor_details.tpb @@ -96,6 +96,7 @@ create or replace type body ut_cursor_details as l_hierarchy_level integer := 1; begin self.cursor_columns_info := ut_cursor_column_tab(); + self.is_anydata := 0; dbms_sql.describe_columns3(a_cursor_number, l_columns_count, l_columns_desc); /** @@ -147,12 +148,13 @@ create or replace type body ut_cursor_details as member function get_missing_join_by_columns( a_expected_columns ut_varchar2_list ) return ut_varchar2_list is l_result ut_varchar2_list; begin + --regexp_replace(c.access_path,'^\/?([^\/]+\/){1}') select fl.column_value bulk collect into l_result from table(a_expected_columns) fl where not exists ( select 1 from table(self.cursor_columns_info) c - where regexp_like(c.access_path, '^'||fl.column_value||'($|/.*)') + where regexp_like(c.filter_path,'^/?'||fl.column_value||'($|/.*)' ) ) order by fl.column_value; return l_result; @@ -181,8 +183,9 @@ create or replace type body ut_cursor_details as bulk collect into l_result.cursor_columns_info from table(self.cursor_columns_info) x where exists( - select 1 from included_columns f where regexp_like( x.access_path, '^/?'||f.col_names||'($|/.*)' ) - ); + select 1 from included_columns f where regexp_like(x.filter_path,'^/?'||f.col_names||'($|/.*)' ) + ) + or x.hierarchy_level = case when self.is_anydata = 1 then 1 else 0 end ; end if; elsif a_match_options.exclude.items.count > 0 then with excluded_columns as ( @@ -193,7 +196,7 @@ create or replace type body ut_cursor_details as bulk collect into l_result.cursor_columns_info from table(self.cursor_columns_info) x where not exists( - select 1 from excluded_columns f where regexp_like( '/'||x.access_path, '^/?'||f.col_names||'($|/.*)' ) + select 1 from excluded_columns f where regexp_like(x.filter_path,'^/?'||f.col_names||'($|/.*)' ) ); end if; @@ -226,8 +229,28 @@ create or replace type body ut_cursor_details as from table(self.cursor_columns_info) t where (a_parent_name is null and parent_name is null and hierarchy_level = 1 and column_name is not null) having count(*) > 0; - return l_result; end; + + member function get_root return varchar2 is + l_root varchar2(250); + begin + if self.cursor_columns_info.count > 0 then + select x.access_path into l_root from table(self.cursor_columns_info) x + where x.hierarchy_level = 1; + else + l_root := null; + end if; + return l_root; + end; + + member procedure strip_root_from_anydata(self in out nocopy ut_cursor_details) is + l_root varchar2(250) := get_root(); + begin + self.is_anydata := 1; + for i in 1..cursor_columns_info.count loop + self.cursor_columns_info(i).filter_path := '/'||ut_utils.strip_prefix(self.cursor_columns_info(i).access_path,l_root); + end loop; + end; end; / diff --git a/source/expectations/data_values/ut_cursor_details.tps b/source/expectations/data_values/ut_cursor_details.tps index c2aa98066..43e70b123 100644 --- a/source/expectations/data_values/ut_cursor_details.tps +++ b/source/expectations/data_values/ut_cursor_details.tps @@ -1,4 +1,4 @@ -create or replace type ut_cursor_details force authid current_user as object ( +create or replace type ut_cursor_details authid current_user as object ( /* utPLSQL - Version 3 Copyright 2016 - 2018 utPLSQL Project @@ -17,6 +17,8 @@ create or replace type ut_cursor_details force authid current_user as object ( */ cursor_columns_info ut_cursor_column_tab, + /*if type is anydata we need to skip level 1 on joinby / inlude / exclude as its artificial cursor*/ + is_anydata number(1,0), constructor function ut_cursor_details(self in out nocopy ut_cursor_details) return self as result, constructor function ut_cursor_details( self in out nocopy ut_cursor_details,a_cursor_number in number @@ -29,9 +31,11 @@ create or replace type ut_cursor_details force authid current_user as object ( a_level in integer, a_access_path in varchar2 ), - member function contains_collection return boolean, - member function get_missing_join_by_columns( a_expected_columns ut_varchar2_list ) return ut_varchar2_list, + member function contains_collection return boolean, + member function get_missing_join_by_columns( a_expected_columns ut_varchar2_list ) return ut_varchar2_list, member procedure filter_columns(self in out nocopy ut_cursor_details, a_match_options ut_matcher_options), - member function get_xml_children(a_parent_name varchar2 := null) return xmltype + member function get_xml_children(a_parent_name varchar2 := null) return xmltype, + member function get_root return varchar2, + member procedure strip_root_from_anydata(self in out nocopy ut_cursor_details) ) / diff --git a/source/expectations/data_values/ut_data_value_anydata.tpb b/source/expectations/data_values/ut_data_value_anydata.tpb index 19917633a..fe9a6a1bc 100644 --- a/source/expectations/data_values/ut_data_value_anydata.tpb +++ b/source/expectations/data_values/ut_data_value_anydata.tpb @@ -61,8 +61,6 @@ create or replace type body ut_data_value_anydata as member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata) is l_refcursor sys_refcursor; - l_ctx number; - l_ut_owner varchar2(250) := ut_utils.ut_owner; cursor_not_open exception; l_cursor_number number; l_anydata_sql varchar2(32767); @@ -84,6 +82,7 @@ create or replace type body ut_data_value_anydata as self.extract_cursor(l_refcursor); l_cursor_number := dbms_sql.to_cursor_number(l_refcursor); self.cursor_details := ut_cursor_details(l_cursor_number); + self.cursor_details.strip_root_from_anydata; dbms_sql.close_cursor(l_cursor_number); elsif not l_refcursor%isopen then raise cursor_not_open; diff --git a/source/expectations/data_values/ut_data_value_refcursor.tpb b/source/expectations/data_values/ut_data_value_refcursor.tpb index ee929d097..d73a3e011 100644 --- a/source/expectations/data_values/ut_data_value_refcursor.tpb +++ b/source/expectations/data_values/ut_data_value_refcursor.tpb @@ -250,8 +250,14 @@ create or replace type body ut_data_value_refcursor as if l_diff_row_count > 0 then l_row_diffs := ut_compound_data_helper.get_rows_diff_by_sql( l_self_cols, l_other_cols, l_self.data_id, l_other.data_id, - l_diff_id, a_match_options.join_by.items, a_match_options.unordered, - a_match_options.ordered_columns(), self.extract_path + l_diff_id, + case + when + l_self.cursor_details.is_anydata = 1 then ut_utils.add_prefix(a_match_options.join_by.items, l_self.cursor_details.get_root) + else + a_match_options.join_by.items + end, + a_match_options.unordered,a_match_options.ordered_columns(), self.extract_path ); l_message := chr(10) ||'Rows: [ ' || l_diff_row_count ||' differences' diff --git a/test/ut3_user/expectations/test_expectation_anydata.pkb b/test/ut3_user/expectations/test_expectation_anydata.pkb index dec64d30d..4838aabff 100644 --- a/test/ut3_user/expectations/test_expectation_anydata.pkb +++ b/test/ut3_user/expectations/test_expectation_anydata.pkb @@ -249,7 +249,7 @@ create or replace package body test_expectation_anydata is l_list ut3.ut_varchar2_list; begin --Arrange - l_list := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/Value','/TEST_DUMMY_OBJECT/ID'); + l_list := ut3.ut_varchar2_list('Value','/ID'); g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>3, "name"=>'A',"Value"=>'1') ); --Act @@ -262,7 +262,7 @@ create or replace package body test_expectation_anydata is l_list varchar2(100); begin --Arrange - l_list := 'TEST_DUMMY_OBJECT/Value,TEST_DUMMY_OBJECT/ID'; + l_list := 'Value,ID'; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); --Act @@ -275,7 +275,7 @@ create or replace package body test_expectation_anydata is l_xpath varchar2(100); begin --Arrange - l_xpath := '//TEST_DUMMY_OBJECT/Value|//TEST_DUMMY_OBJECT/ID'; + l_xpath := '//Value|//ID'; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); --Act @@ -301,7 +301,7 @@ create or replace package body test_expectation_anydata is l_list ut3.ut_varchar2_list; begin --Arrange - l_list := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/Value','TEST_DUMMY_OBJECT/ID'); + l_list := ut3.ut_varchar2_list('Value','ID'); g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'b',"Value"=>'0') ); --Act @@ -314,7 +314,7 @@ create or replace package body test_expectation_anydata is l_xpath varchar2(100); begin --Arrange - l_xpath := 'TEST_DUMMY_OBJECT/key,TEST_DUMMY_OBJECT/ID'; + l_xpath := 'key,ID'; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); --Act @@ -327,7 +327,7 @@ create or replace package body test_expectation_anydata is l_xpath varchar2(100); begin --Arrange - l_xpath := '//TEST_DUMMY_OBJECT/key|//TEST_DUMMY_OBJECT/ID'; + l_xpath := '//key|//ID'; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); --Act @@ -340,7 +340,7 @@ create or replace package body test_expectation_anydata is l_include varchar2(100); begin --Arrange - l_include := ' BadAttributeName, TEST_DUMMY_OBJECT/ID '; + l_include := ' BadAttributeName, ID '; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); --Act @@ -354,8 +354,8 @@ create or replace package body test_expectation_anydata is l_include varchar2(100); begin --Arrange - l_include := 'TEST_DUMMY_OBJECT/key,TEST_DUMMY_OBJECT/ID,TEST_DUMMY_OBJECT/Value'; - l_exclude := '//TEST_DUMMY_OBJECT/key|//TEST_DUMMY_OBJECT/Value'; + l_include := 'key,ID,Value'; + l_exclude := '//key|//Value'; g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); --Act @@ -371,8 +371,8 @@ create or replace package body test_expectation_anydata is l_actual varchar2(32767); begin --Arrange - l_include := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/key','TEST_DUMMY_OBJECT/ID','TEST_DUMMY_OBJECT/Value'); - l_exclude := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/key','TEST_DUMMY_OBJECT/Value'); + l_include := ut3.ut_varchar2_list('key','ID','Value'); + l_exclude := ut3.ut_varchar2_list('key','Value'); g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); --Act @@ -548,7 +548,7 @@ Rows: [ 60 differences, showing first 20 ] l_expected ut3_tester_helper.test_dummy_object_list; l_list ut3.ut_varchar2_list; begin - l_list := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/Value','TEST_DUMMY_OBJECT/ID'); + l_list := ut3.ut_varchar2_list('Value','ID'); --Arrange select ut3_tester_helper.test_dummy_object( rownum, 'SomethingsDifferent '||rownum, rownum) bulk collect into l_actual @@ -567,7 +567,7 @@ Rows: [ 60 differences, showing first 20 ] l_expected ut3_tester_helper.test_dummy_object_list; l_list ut3.ut_varchar2_list; begin - l_list := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/Value','TEST_DUMMY_OBJECT/ID'); + l_list := ut3.ut_varchar2_list('Value','ID'); --Arrange select ut3_tester_helper.test_dummy_object( rownum*2, 'Something '||rownum, rownum*2) bulk collect into l_actual @@ -588,7 +588,7 @@ Rows: [ 60 differences, showing first 20 ] l_actual_message varchar2(32767); l_expected_message varchar2(32767); begin - l_list := ut3.ut_varchar2_list('TEST_DUMMY_OBJECT/name'); + l_list := ut3.ut_varchar2_list('name'); --Arrange select ut3_tester_helper.test_dummy_object( rownum, 'SomethingsDifferent '||rownum, rownum) bulk collect into l_actual @@ -602,7 +602,10 @@ Rows: [ 60 differences, showing first 20 ] l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] %Diff: %Rows: [ 2 differences ] -%All rows are different as the columns are not matching.]'; +%Row No. 1 - Actual: SomethingsDifferent 1 +%Row No. 1 - Expected: Something 1 +%Row No. 2 - Actual: SomethingsDifferent 2 +%Row No. 2 - Expected: Something 2]'; l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); --Assert ut.expect(l_actual_message).to_be_like(l_expected_message); @@ -841,7 +844,7 @@ Rows: [ 60 differences, showing first 20 ] from dual connect by level <=2 order by rownum desc; --Act - ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('TEST_DUMMY_OBJECT/ID'); + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('ID'); ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; @@ -860,7 +863,7 @@ Rows: [ 60 differences, showing first 20 ] from dual connect by level <=2 order by rownum desc; --Act - ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('TEST_DUMMY_OBJECT/ID'); + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('ID'); l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] %Diff: %Rows: [ 3 differences ] @@ -928,7 +931,7 @@ Rows: [ 60 differences, showing first 20 ] g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); --Act - ut3.ut.expect(g_test_actual).to_equal(g_test_expected).join_by('TEST_DUMMY_OBJECT/ID'); + ut3.ut.expect(g_test_actual).to_equal(g_test_expected).join_by('ID'); ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end;