Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7b87c35

Browse files
authored
Merge pull request #619 from lwasylow/junitreporter
New reporter for Microsoft Team Fundation Server (TFS)
2 parents 8264e12 + 2a8da3d commit 7b87c35

13 files changed

Lines changed: 422 additions & 0 deletions

docs/images/tfs_details.png

70.2 KB
Loading

docs/images/tfs_summary.png

23.4 KB
Loading

docs/userguide/reporters.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ Providing invalid paths or paths to non-existing files will result in failure wh
9595

9696
For details on how to invoke reporter with paths, see the **Coverage reporters** section.
9797

98+
# TFS / VSTS Reporter
99+
If you are using [TFS](https://www.visualstudio.com/tfs/) or [VSTS](https://www.visualstudio.com/team-services/) to do static code analysis for you PLSQL projects and run builds, your code analysis can benefit from code coverage and test results. TFS reporter is designed specifically to [work with Microsoft Team Fundation Server](https://docs.microsoft.com/en-us/vsts/build-release/tasks/test/publish-test-results?view=vsts) report format which is very old version of [JUnit](https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd).
100+
Main diffrence between standard JUnit is that <testsuite> elements cannot be nested and attribute skipped is not present.
101+
102+
utPLSQL provides test reporter to for TFS / VSTS server:
103+
- `ut_tfs_junit_reporter` - provides an XML output of each test executed per each project test file (package)
104+
105+
Example of test report from TFS CI server.
106+
107+
Summary:
108+
109+
![tfs_junit_reporter_outputs](../images/tfs_summary.png)
110+
111+
Details:
112+
113+
![tfs_junit_reporter_outputs](../images/tfs_details.png)
114+
115+
98116
# Coverage reporters
99117

100118
utPLSQL comes with a set of build-in coverage reporters. Have a look into the [coverage documentation](coverage.md) to learn more about them.

source/create_synonyms_and_grants_for_public.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ grant execute on &&ut3_owner..ut to public;
4949
grant execute on &&ut3_owner..ut_runner to public;
5050
grant execute on &&ut3_owner..ut_teamcity_reporter to public;
5151
grant execute on &&ut3_owner..ut_xunit_reporter to public;
52+
grant execute on &&ut3_owner..ut_tfs_junit_reporter to public;
5253
grant execute on &&ut3_owner..ut_documentation_reporter to public;
5354
grant execute on &&ut3_owner..ut_coverage_html_reporter to public;
5455
grant execute on &&ut3_owner..ut_coverage_sonar_reporter to public;
@@ -106,6 +107,7 @@ create public synonym ut for &&ut3_owner..ut;
106107
create public synonym ut_runner for &&ut3_owner..ut_runner;
107108
create public synonym ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter;
108109
create public synonym ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter;
110+
create public synonym ut_tfs_junit_reporter for &&ut3_owner..ut_tfs_junit_reporter;
109111
create public synonym ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter;
110112
create public synonym ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter;
111113
create public synonym ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter;

source/create_synonyms_and_grants_for_user.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ grant execute on &&ut3_owner..ut to &ut3_user;
6969
grant execute on &&ut3_owner..ut_runner to &ut3_user;
7070
grant execute on &&ut3_owner..ut_teamcity_reporter to &ut3_user;
7171
grant execute on &&ut3_owner..ut_xunit_reporter to &ut3_user;
72+
grant execute on &&ut3_owner..ut_tfs_junit_reporter to &ut3_user;
7273
grant execute on &&ut3_owner..ut_documentation_reporter to &ut3_user;
7374
grant execute on &&ut3_owner..ut_coverage_html_reporter to &ut3_user;
7475
grant execute on &&ut3_owner..ut_coverage_sonar_reporter to &ut3_user;
@@ -125,6 +126,7 @@ create or replace synonym &ut3_user..ut for &&ut3_owner..ut;
125126
create or replace synonym &ut3_user..ut_runner for &&ut3_owner..ut_runner;
126127
create or replace synonym &ut3_user..ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter;
127128
create or replace synonym &ut3_user..ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter;
129+
create or replace synonym &ut3_user..ut_tfs_junit_reporter for &&ut3_owner..ut_tfs_junit_reporter;
128130
create or replace synonym &ut3_user..ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter;
129131
create or replace synonym &ut3_user..ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter;
130132
create or replace synonym &ut3_user..ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter;

source/install.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ prompt Installing PLSQL profiler objects into &&ut3_owner schema
239239
@@install_component.sql 'reporters/ut_teamcity_reporter.tpb'
240240
@@install_component.sql 'reporters/ut_xunit_reporter.tps'
241241
@@install_component.sql 'reporters/ut_xunit_reporter.tpb'
242+
@@install_component.sql 'reporters/ut_tfs_junit_reporter.tps'
243+
@@install_component.sql 'reporters/ut_tfs_junit_reporter.tpb'
242244
@@install_component.sql 'reporters/ut_sonar_test_reporter.tps'
243245
@@install_component.sql 'reporters/ut_sonar_test_reporter.tpb'
244246

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
create or replace type body ut_tfs_junit_reporter is
2+
/*
3+
utPLSQL - Version 3
4+
Copyright 2016 - 2017 utPLSQL Project
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"):
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
constructor function ut_tfs_junit_reporter(self in out nocopy ut_tfs_junit_reporter) return self as result is
20+
begin
21+
self.init($$plsql_unit);
22+
return;
23+
end;
24+
25+
overriding member procedure after_calling_run(self in out nocopy ut_tfs_junit_reporter, a_run in ut_run) is
26+
begin
27+
junit_version_one(a_run);
28+
end;
29+
30+
member procedure junit_version_one(self in out nocopy ut_tfs_junit_reporter,a_run in ut_run) is
31+
l_suite_id integer := 0;
32+
l_tests_count integer := a_run.results_count.disabled_count + a_run.results_count.success_count +
33+
a_run.results_count.failure_count + a_run.results_count.errored_count;
34+
35+
function get_common_suite_attributes(a_item ut_suite_item) return varchar2 is
36+
begin
37+
return ' errors="' ||a_item.results_count.errored_count || '"' ||
38+
' failures="' || a_item.results_count.failure_count ||
39+
'" name="' || dbms_xmlgen.convert(nvl(a_item.description, a_item.name)) || '"' ||
40+
' time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '" '||
41+
' timestamp="' || to_char(sysdate,'RRRR-MM-DD"T"HH24:MI:SS') || '" '||
42+
' hostname="' || sys_context('USERENV','HOST') || '" ';
43+
end;
44+
45+
function get_common_testcase_attributes(a_item ut_suite_item) return varchar2 is
46+
begin
47+
return ' name="' || dbms_xmlgen.convert(nvl(a_item.description, a_item.name)) || '"' ||
48+
' time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '"';
49+
end;
50+
51+
function get_path(a_path_with_name varchar2, a_name varchar2) return varchar2 is
52+
begin
53+
return regexp_substr(a_path_with_name, '(.*)\.' ||a_name||'$',subexpression=>1);
54+
end;
55+
56+
procedure print_test_results(a_test ut_test) is
57+
l_lines ut_varchar2_list;
58+
l_output clob;
59+
begin
60+
self.print_text('<testcase classname="' || dbms_xmlgen.convert(get_path(a_test.path, a_test.name)) || '" ' ||
61+
get_common_testcase_attributes(a_test) || '>');
62+
/*
63+
According to specs :
64+
- A failure is a test which the code has explicitly failed by using the mechanisms for that purpose.
65+
e.g., via an assertEquals
66+
- An errored test is one that had an unanticipated problem.
67+
e.g., an unchecked throwable; or a problem with the implementation of the test.
68+
*/
69+
70+
if a_test.result = ut_utils.tr_error then
71+
self.print_text('<error type="error" message="Error while executing '||a_test.name||'">');
72+
self.print_text('<![CDATA[');
73+
self.print_clob(ut_utils.table_to_clob(a_test.get_error_stack_traces()));
74+
self.print_text(']]>');
75+
self.print_text('</error>');
76+
-- Do not count error as failure
77+
elsif a_test.result = ut_utils.tr_failure then
78+
self.print_text('<failure type="failure" message="Test '||a_test.name||' failed">');
79+
self.print_text('<![CDATA[');
80+
for i in 1 .. a_test.failed_expectations.count loop
81+
l_lines := a_test.failed_expectations(i).get_result_lines();
82+
for j in 1 .. l_lines.count loop
83+
self.print_text(l_lines(j));
84+
end loop;
85+
self.print_text(a_test.failed_expectations(i).caller_info);
86+
end loop;
87+
self.print_text(']]>');
88+
self.print_text('</failure>');
89+
end if;
90+
91+
self.print_text('</testcase>');
92+
end;
93+
94+
procedure print_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is
95+
l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count +
96+
a_suite.results_count.failure_count + a_suite.results_count.errored_count;
97+
l_suite ut_suite;
98+
begin
99+
100+
for i in 1 .. a_suite.items.count loop
101+
if a_suite.items(i) is of(ut_logical_suite) then
102+
print_suite_results(treat(a_suite.items(i) as ut_logical_suite), a_suite_id);
103+
end if;
104+
end loop;
105+
106+
if a_suite is of(ut_suite) then
107+
a_suite_id := a_suite_id + 1;
108+
self.print_text('<testsuite tests="' || l_tests_count || '"' || ' id="' || a_suite_id || '"' || ' package="' ||
109+
dbms_xmlgen.convert(a_suite.path) || '" ' || get_common_suite_attributes(a_suite) || '>');
110+
self.print_text('<properties/>');
111+
for i in 1 .. a_suite.items.count loop
112+
if a_suite.items(i) is of(ut_test) then
113+
print_test_results(treat(a_suite.items(i) as ut_test));
114+
end if;
115+
end loop;
116+
l_suite := treat(a_suite as ut_suite);
117+
if l_suite.before_all.serveroutput is not null or l_suite.after_all.serveroutput is not null then
118+
self.print_text('<system-out>');
119+
self.print_text('<![CDATA[');
120+
self.print_clob(l_suite.get_serveroutputs());
121+
self.print_text(']]>');
122+
self.print_text('</system-out>');
123+
else
124+
self.print_text('<system-out/>');
125+
end if;
126+
127+
if l_suite.before_all.error_stack is not null or l_suite.after_all.error_stack is not null then
128+
self.print_text('<system-err>');
129+
self.print_text('<![CDATA[');
130+
self.print_text(trim(l_suite.before_all.error_stack) || trim(chr(10) || chr(10) || l_suite.after_all.error_stack));
131+
self.print_text(']]>');
132+
self.print_text('</system-err>');
133+
else
134+
self.print_text('<system-err/>');
135+
end if;
136+
self.print_text('</testsuite>');
137+
end if;
138+
end;
139+
140+
begin
141+
l_suite_id := 0;
142+
self.print_text('<testsuites>');
143+
for i in 1 .. a_run.items.count loop
144+
print_suite_results(treat(a_run.items(i) as ut_logical_suite), l_suite_id);
145+
end loop;
146+
self.print_text('</testsuites>');
147+
end;
148+
149+
overriding member function get_description return varchar2 as
150+
begin
151+
return 'Provides outcomes in a format conforming with JUnit version for TFS / VSTS.
152+
As defined by specs :https://docs.microsoft.com/en-us/vsts/build-release/tasks/test/publish-test-results?view=vsts
153+
Version is based on windy road junit https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd.';
154+
end;
155+
156+
end;
157+
/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
create or replace type ut_tfs_junit_reporter under ut_output_reporter_base(
2+
/*
3+
utPLSQL - Version 3
4+
Copyright 2016 - 2017 utPLSQL Project
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"):
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
/**
19+
* The JUnit reporter for publishing results in TFS/VSTS
20+
* Provides outcomes in a format conforming with specs as defined in:
21+
* https://docs.microsoft.com/en-us/vsts/build-release/tasks/test/publish-test-results?view=vsts
22+
*/
23+
24+
constructor function ut_tfs_junit_reporter(
25+
self in out nocopy ut_tfs_junit_reporter
26+
) return self as result,
27+
28+
overriding member procedure after_calling_run(self in out nocopy ut_tfs_junit_reporter, a_run in ut_run),
29+
member procedure junit_version_one(self in out nocopy ut_tfs_junit_reporter, a_run in ut_run),
30+
31+
overriding member function get_description return varchar2
32+
)
33+
not final
34+
/

source/uninstall.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ drop type ut_teamcity_reporter force;
196196

197197
drop type ut_xunit_reporter force;
198198

199+
drop type ut_tfs_junit_reporter force;
200+
199201
drop type ut_event_listener force;
200202

201203
drop type ut_output_reporter_base force;

test/api/test_ut_runner.pkb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ end;';
288288
select 'UT3.UT_DOCUMENTATION_REPORTER', 'Y' from dual union all
289289
select 'UT3.UT_SONAR_TEST_REPORTER', 'Y' from dual union all
290290
select 'UT3.UT_TEAMCITY_REPORTER', 'Y' from dual union all
291+
select 'UT3.UT_TFS_JUNIT_REPORTER', 'Y' from dual union all
291292
select 'UT3.UT_XUNIT_REPORTER', 'Y' from dual;
292293
--Act
293294
open l_actual for select * from table(ut3.ut_runner.GET_REPORTERS_LIST()) order by 1;

0 commit comments

Comments
 (0)