├── .github
├── dependabot.yml
└── workflows
│ ├── build-test.yml
│ ├── lint.yml
│ └── opam-dependency-submission.yml
├── .gitignore
├── .ocamlformat
├── .travis.yml
├── CHANGES.md
├── LICENSE
├── Makefile
├── README.md
├── alcotest
├── dune
├── junit_alcotest.ml
├── junit_alcotest.mli
└── test
│ ├── alcotest_report.expected
│ ├── alcotest_report.ml
│ └── dune
├── doc
├── api.odocl
├── dev.odocl
└── doc.odocl
├── dune-project
├── junit.opam
├── junit
├── dune
├── junit.ml
├── junit.mli
├── junit_xml.ml
├── junit_xml.mli
└── test
│ ├── dune
│ ├── simple.expected
│ └── simple.ml
├── junit_alcotest.opam
├── junit_ounit.opam
├── ounit
├── dune
├── junit_ounit.ml
└── junit_ounit.mli
└── schemes
├── gist.xsd
├── jenkins.xsd
├── junit-schema.xsd
└── windyroad.xsd
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: github-actions
4 | directory: /
5 | schedule:
6 | interval: monthly
7 |
--------------------------------------------------------------------------------
/.github/workflows/build-test.yml:
--------------------------------------------------------------------------------
1 | name: Build and Test
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | jobs:
8 | build-and-test:
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | os:
13 | - macos-latest
14 | - ubuntu-latest
15 | # - windows-latest
16 | ocaml-version:
17 | - 4.14
18 | - 5.2
19 |
20 | runs-on: ${{ matrix.os }}
21 |
22 | steps:
23 | - name: Checkout code
24 | uses: actions/checkout@v4
25 |
26 | - name: Use OCaml ${{ matrix.ocaml-version }}
27 | uses: ocaml/setup-ocaml@v3
28 | with:
29 | ocaml-compiler: ${{ matrix.ocaml-version }}
30 | dune-cache: true
31 | allow-prerelease-opam: true
32 |
33 | - run: opam install . --deps-only --with-test
34 |
35 | - name: build project
36 | run: opam exec -- dune build
37 |
38 | - name: run test
39 | run: opam exec -- dune runtest
40 |
41 | - name: junit report
42 | uses: dorny/test-reporter@v2
43 | if: success() || failure() # run this step even if previous step failed
44 | with:
45 | name: Test Report
46 | path: "_build/default/alcotest/test/*.xml,_build/default/junit/test/*.xml"
47 | reporter: java-junit
48 | fail-on-error: false # Report results but don't fail the build
49 | fail-on-empty: true # Use an empty test report to detect when something failed with the test runner
50 |
51 | - run: opam install . --deps-only --with-test --criteria='+removed,+count[version-lag,solution]' --solver=builtin-0install
52 |
53 | - name: build project
54 | run: opam exec -- dune build
55 |
56 | - name: run test
57 | run: opam exec -- dune runtest
58 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | jobs:
8 | lint-fmt:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v4
13 |
14 | - name: Use OCaml 5.2
15 | uses: ocaml/setup-ocaml@v3
16 | with:
17 | ocaml-compiler: 5.2
18 | dune-cache: true
19 | allow-prerelease-opam: true
20 |
21 | - name: Lint fmt
22 | uses: ocaml/setup-ocaml/lint-fmt@v3
23 |
24 | # auto fix formatting, Thanks to robur.coop for the implementation
25 | # https://discuss.ocaml.org/t/ocamlformat-and-github-actions/15464
26 | # lint-auto-fmt:
27 | # runs-on: ubuntu-latest
28 | # steps:
29 | # - name: Checkout code
30 | # uses: actions/checkout@v4
31 |
32 | # - name: Use OCaml 5.2
33 | # uses: ocaml/setup-ocaml@v3
34 | # with:
35 | # ocaml-compiler: 5.2
36 | # dune-cache: true
37 | # allow-prerelease-opam: true
38 |
39 | # - name: Install ocamlformat
40 | # run: grep '^version' .ocamlformat | cut -d '=' -f 2 | xargs -I V opam install ocamlformat=V
41 |
42 | # - name: Format code
43 | # run: |
44 | # git ls-files '*.ml' '*.mli' | xargs opam exec -- ocamlformat --inplace
45 |
46 | # - name: Check for modified files
47 | # id: git-check
48 | # run: echo "modified=$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi)" >> $GITHUB_OUTPUT
49 |
50 | # - name: Commit and push changes
51 | # if: ${{ steps.git-check.outputs.modified == 'true' }}
52 | # run: |
53 | # git config --global user.name "Automated ocamlformat GitHub action, developed by robur.coop"
54 | # git config --global user.email "autoformat@robur.coop"
55 | # git add -A
56 | # git commit -m "formatted code"
57 | # git push
58 |
59 | lint-opam:
60 | runs-on: ubuntu-latest
61 | steps:
62 | - name: Checkout code
63 | uses: actions/checkout@v4
64 |
65 | - name: Use OCaml 5.2
66 | uses: ocaml/setup-ocaml@v3
67 | with:
68 | ocaml-compiler: 5.2
69 | dune-cache: true
70 | allow-prerelease-opam: true
71 |
72 | - name: Lint opam
73 | uses: ocaml/setup-ocaml/lint-opam@v3
74 |
75 | lint-doc:
76 | runs-on: ubuntu-latest
77 | steps:
78 | - name: Checkout code
79 | uses: actions/checkout@v4
80 |
81 | - name: Use OCaml 5.2
82 | uses: ocaml/setup-ocaml@v3
83 | with:
84 | ocaml-compiler: 5.2
85 | dune-cache: true
86 | allow-prerelease-opam: true
87 |
88 | - name: Lint doc
89 | uses: ocaml/setup-ocaml/lint-doc@v3
90 |
--------------------------------------------------------------------------------
/.github/workflows/opam-dependency-submission.yml:
--------------------------------------------------------------------------------
1 | name: Opam Dependency Submission
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | jobs:
8 | opam-dependency-submission:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout tree
12 | uses: actions/checkout@v4
13 |
14 | - name: Set-up OCaml 5.2
15 | uses: ocaml/setup-ocaml@v3
16 | with:
17 | ocaml-compiler: 5.2
18 | dune-cache: true
19 | allow-prerelease-opam: true
20 |
21 | - name: Opam Dependency Submission
22 | uses: ocaml/setup-ocaml/analysis@v3
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .merlin
2 | *.install
3 | _build
4 |
--------------------------------------------------------------------------------
/.ocamlformat:
--------------------------------------------------------------------------------
1 | profile=janestreet
2 | version=0.27.0
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | sudo: required
3 | install: wget https://raw.githubusercontent.com/ocaml/ocaml-travisci-skeleton/master/.travis-opam.sh
4 | script: bash -ex .travis-opam.sh
5 | env:
6 | matrix:
7 | - OCAML_VERSION=4.05 PACKAGE="junit" TESTS=true
8 | - OCAML_VERSION=4.05 PACKAGE="junit_alcotest" TESTS=true
9 | - OCAML_VERSION=4.05 PACKAGE="junit_ounit" TESTS=true
10 | - OCAML_VERSION=4.06 PACKAGE="junit" TESTS=true
11 | - OCAML_VERSION=4.06 PACKAGE="junit_alcotest" TESTS=true
12 | - OCAML_VERSION=4.06 PACKAGE="junit_ounit" TESTS=true
13 | - OCAML_VERSION=4.07 PACKAGE="junit" TESTS=true
14 | - OCAML_VERSION=4.07 PACKAGE="junit_alcotest" TESTS=true
15 | - OCAML_VERSION=4.07 PACKAGE="junit_ounit" TESTS=true
16 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## 2.3.0 (2025-04-21)
2 |
3 | - upgrade minimal alcotest to 1.9.0
4 |
5 | ## 2.2.0 (2024-12-25)
6 |
7 | - fix bug marking alcotest skipped tests as passed
8 | - reraise exceptions to clean backtraces
9 | - expose arguments of `Alcotest.run`
10 | - increase dependency on alcotest to 1.8.0
11 |
12 | ## 2.1.0 (2024-12-22)
13 |
14 | - add skipped attribute to testsuite (#10)
15 | - fix skipped support for alcotest (#10)
16 | - depend on ounit2
17 |
18 | ## 2.0.1 (2019-02-16)
19 |
20 | - remove pkg
21 | - migrate to opam 2
22 | - migrate to dune
23 |
24 | ## 2.0 (2017-04-30)
25 |
26 | - add alcotest and ounit support
27 |
28 | ## 1.0 (2017-09-5)
29 |
30 | - move to jbuilder
31 | - `Testsuite.make` expects `()` as last argument.
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | As a special exception to the GNU Lesser General Public License, you
2 | may link, statically or dynamically, a "work that uses the Library"
3 | with a publicly distributed version of the Library to produce an
4 | executable file containing portions of the Library, and distribute
5 | that executable file under terms of your choice, without any of the
6 | additional requirements listed in clause 6 of the GNU Library General
7 | Public License. By "a publicly distributed version of the Library", we
8 | mean either the unmodified Library as distributed by the copyright
9 | holder, or a modified version of the Library that is distributed under
10 | the conditions defined in clause 3 of the GNU Library General Public
11 | License. This exception does not however invalidate any other reasons
12 | why the executable file might be covered by the GNU Lesser General
13 | Public License.
14 |
15 | GNU LESSER GENERAL PUBLIC LICENSE
16 | Version 3, 29 June 2007
17 |
18 | Copyright (C) 2007 Free Software Foundation, Inc.
19 | Everyone is permitted to copy and distribute verbatim copies
20 | of this license document, but changing it is not allowed.
21 |
22 |
23 | This version of the GNU Lesser General Public License incorporates
24 | the terms and conditions of version 3 of the GNU General Public
25 | License, supplemented by the additional permissions listed below.
26 |
27 | 0. Additional Definitions.
28 |
29 | As used herein, "this License" refers to version 3 of the GNU Lesser
30 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
31 | General Public License.
32 |
33 | "The Library" refers to a covered work governed by this License,
34 | other than an Application or a Combined Work as defined below.
35 |
36 | An "Application" is any work that makes use of an interface provided
37 | by the Library, but which is not otherwise based on the Library.
38 | Defining a subclass of a class defined by the Library is deemed a mode
39 | of using an interface provided by the Library.
40 |
41 | A "Combined Work" is a work produced by combining or linking an
42 | Application with the Library. The particular version of the Library
43 | with which the Combined Work was made is also called the "Linked
44 | Version".
45 |
46 | The "Minimal Corresponding Source" for a Combined Work means the
47 | Corresponding Source for the Combined Work, excluding any source code
48 | for portions of the Combined Work that, considered in isolation, are
49 | based on the Application, and not on the Linked Version.
50 |
51 | The "Corresponding Application Code" for a Combined Work means the
52 | object code and/or source code for the Application, including any data
53 | and utility programs needed for reproducing the Combined Work from the
54 | Application, but excluding the System Libraries of the Combined Work.
55 |
56 | 1. Exception to Section 3 of the GNU GPL.
57 |
58 | You may convey a covered work under sections 3 and 4 of this License
59 | without being bound by section 3 of the GNU GPL.
60 |
61 | 2. Conveying Modified Versions.
62 |
63 | If you modify a copy of the Library, and, in your modifications, a
64 | facility refers to a function or data to be supplied by an Application
65 | that uses the facility (other than as an argument passed when the
66 | facility is invoked), then you may convey a copy of the modified
67 | version:
68 |
69 | a) under this License, provided that you make a good faith effort to
70 | ensure that, in the event an Application does not supply the
71 | function or data, the facility still operates, and performs
72 | whatever part of its purpose remains meaningful, or
73 |
74 | b) under the GNU GPL, with none of the additional permissions of
75 | this License applicable to that copy.
76 |
77 | 3. Object Code Incorporating Material from Library Header Files.
78 |
79 | The object code form of an Application may incorporate material from
80 | a header file that is part of the Library. You may convey such object
81 | code under terms of your choice, provided that, if the incorporated
82 | material is not limited to numerical parameters, data structure
83 | layouts and accessors, or small macros, inline functions and templates
84 | (ten or fewer lines in length), you do both of the following:
85 |
86 | a) Give prominent notice with each copy of the object code that the
87 | Library is used in it and that the Library and its use are
88 | covered by this License.
89 |
90 | b) Accompany the object code with a copy of the GNU GPL and this license
91 | document.
92 |
93 | 4. Combined Works.
94 |
95 | You may convey a Combined Work under terms of your choice that,
96 | taken together, effectively do not restrict modification of the
97 | portions of the Library contained in the Combined Work and reverse
98 | engineering for debugging such modifications, if you also do each of
99 | the following:
100 |
101 | a) Give prominent notice with each copy of the Combined Work that
102 | the Library is used in it and that the Library and its use are
103 | covered by this License.
104 |
105 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
106 | document.
107 |
108 | c) For a Combined Work that displays copyright notices during
109 | execution, include the copyright notice for the Library among
110 | these notices, as well as a reference directing the user to the
111 | copies of the GNU GPL and this license document.
112 |
113 | d) Do one of the following:
114 |
115 | 0) Convey the Minimal Corresponding Source under the terms of this
116 | License, and the Corresponding Application Code in a form
117 | suitable for, and under terms that permit, the user to
118 | recombine or relink the Application with a modified version of
119 | the Linked Version to produce a modified Combined Work, in the
120 | manner specified by section 6 of the GNU GPL for conveying
121 | Corresponding Source.
122 |
123 | 1) Use a suitable shared library mechanism for linking with the
124 | Library. A suitable mechanism is one that (a) uses at run time
125 | a copy of the Library already present on the user's computer
126 | system, and (b) will operate properly with a modified version
127 | of the Library that is interface-compatible with the Linked
128 | Version.
129 |
130 | e) Provide Installation Information, but only if you would otherwise
131 | be required to provide such information under section 6 of the
132 | GNU GPL, and only to the extent that such information is
133 | necessary to install and execute a modified version of the
134 | Combined Work produced by recombining or relinking the
135 | Application with a modified version of the Linked Version. (If
136 | you use option 4d0, the Installation Information must accompany
137 | the Minimal Corresponding Source and Corresponding Application
138 | Code. If you use option 4d1, you must provide the Installation
139 | Information in the manner specified by section 6 of the GNU GPL
140 | for conveying Corresponding Source.)
141 |
142 | 5. Combined Libraries.
143 |
144 | You may place library facilities that are a work based on the
145 | Library side by side in a single library together with other library
146 | facilities that are not Applications and are not covered by this
147 | License, and convey such a combined library under terms of your
148 | choice, if you do both of the following:
149 |
150 | a) Accompany the combined library with a copy of the same work based
151 | on the Library, uncombined with any other library facilities,
152 | conveyed under the terms of this License.
153 |
154 | b) Give prominent notice with the combined library that part of it
155 | is a work based on the Library, and explaining where to find the
156 | accompanying uncombined form of the same work.
157 |
158 | 6. Revised Versions of the GNU Lesser General Public License.
159 |
160 | The Free Software Foundation may publish revised and/or new versions
161 | of the GNU Lesser General Public License from time to time. Such new
162 | versions will be similar in spirit to the present version, but may
163 | differ in detail to address new problems or concerns.
164 |
165 | Each version is given a distinguishing version number. If the
166 | Library as you received it specifies that a certain numbered version
167 | of the GNU Lesser General Public License "or any later version"
168 | applies to it, you have the option of following the terms and
169 | conditions either of that published version or of any later version
170 | published by the Free Software Foundation. If the Library as you
171 | received it does not specify a version number of the GNU Lesser
172 | General Public License, you may choose any version of the GNU Lesser
173 | General Public License ever published by the Free Software Foundation.
174 |
175 | If the Library as you received it specifies that a proxy can decide
176 | whether future versions of the GNU Lesser General Public License shall
177 | apply, that proxy's public statement of acceptance of any version is
178 | permanent authorization for you to choose that version for the
179 | Library.
180 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | build:
2 | dune build
3 |
4 | doc:
5 | dune build @doc
6 |
7 | test:
8 | dune runtest
9 |
10 | clean:
11 | dune clean
12 |
13 | fmt:
14 | dune build @fmt --auto-promote
15 |
16 | .PHONY: examples doc test build fmt
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OCaml JUnit
2 |
3 | ocaml-junit is a package for the creation of JUnit XML reports. It
4 | provides a typed API to produce valid reports. They are supposed to be
5 | accepted by Jenkins.
6 |
7 | It comes with two packages for support of OUnit and Alcotest.
8 |
9 | ## Installation
10 |
11 | ```
12 | opam install junit junit_ounit junit_alcotest
13 | ```
14 |
15 | ## Documentation
16 |
17 | Available [here](https://khady.github.io/ocaml-junit/)
18 |
19 | ## References:
20 |
21 | - [Jenkins](https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd)
22 | - [JUnit-Schema](https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd)
23 | - [Windyroad](http://windyroad.com.au/dl/Open%20Source/JUnit.xsd)
24 | - [a gist](https://gist.github.com/erikd/4192748)
25 |
26 | Those files are archived in directory [`schemes`](schemes)
27 |
28 | License: LGPL either version 3 of the License, or (at your option) any
29 | later version with OCaml linking exception.
30 |
--------------------------------------------------------------------------------
/alcotest/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name junit_alcotest)
3 | (public_name junit_alcotest)
4 | (wrapped false)
5 | (synopsis "JUnit XML reports generation for alcotest tests")
6 | (libraries junit alcotest))
7 |
--------------------------------------------------------------------------------
/alcotest/junit_alcotest.ml:
--------------------------------------------------------------------------------
1 | module A = Alcotest
2 |
3 | external reraise : exn -> 'a = "%reraise"
4 |
5 | type exit = unit -> unit
6 |
7 | let push l v = l := v :: !l
8 |
9 | let wrap_test ?classname handle_result (name, s, test) =
10 | let classname =
11 | (* The 'classname' attribute may not be empty, and should contain a period
12 | for best rendering in Jenkins by junit-plugin.
13 | For example, classname="foo.bar.baz" is rendered as a package "foo.bar"
14 | containing a class "baz" containing one or more test cases with their
15 | own name. *)
16 | match classname with
17 | | None | Some "" -> name
18 | | Some path -> path
19 | in
20 | let test () =
21 | try
22 | test ();
23 | Junit.Testcase.pass ~name ~classname ~time:0. |> handle_result
24 | with
25 | | Failure exn_msg as exn ->
26 | Junit.Testcase.failure
27 | ~name
28 | ~classname
29 | ~time:0.
30 | ~typ:"not expected result"
31 | ~message:"test failed"
32 | exn_msg
33 | |> handle_result;
34 | reraise exn
35 | | Alcotest_engine.V1.Core.Skip as exn ->
36 | Junit.Testcase.skipped ~name ~classname ~time:0. |> handle_result;
37 | reraise exn
38 | | exn ->
39 | let exn_msg = Printexc.to_string exn in
40 | Junit.Testcase.error
41 | ~name
42 | ~classname
43 | ~time:0.
44 | ~typ:"exception raised"
45 | ~message:"test crashed"
46 | exn_msg
47 | |> handle_result;
48 | reraise exn
49 | in
50 | name, s, test
51 | ;;
52 |
53 | let run_and_report
54 | ?stdout
55 | ?stderr
56 | ?(and_exit = true)
57 | ?verbose
58 | ?compact
59 | ?tail_errors
60 | ?quick_only
61 | ?show_errors
62 | ?json
63 | ?filter
64 | ?log_dir
65 | ?bail
66 | ?record_backtrace
67 | ?ci
68 | ?package
69 | ?timestamp
70 | ?argv
71 | name
72 | tests
73 | =
74 | let testcases = ref [] in
75 | let testsuite = Junit.Testsuite.make ?package ?timestamp ~name () in
76 | let tests =
77 | List.map
78 | (fun (title, test_set) ->
79 | let classname = Printf.sprintf "%s.%s" name title in
80 | title, List.map (wrap_test ~classname (push testcases)) test_set)
81 | tests
82 | in
83 | let exit =
84 | try
85 | A.run
86 | ?stdout
87 | ?stderr
88 | ?verbose
89 | ?compact
90 | ?tail_errors
91 | ?quick_only
92 | ?show_errors
93 | ?json
94 | ?filter
95 | ?log_dir
96 | ?bail
97 | ?record_backtrace
98 | ?ci
99 | ?argv
100 | ~and_exit:false
101 | name
102 | tests;
103 | fun () -> if and_exit then exit 0 else ()
104 | with
105 | | A.Test_error as exn -> fun () -> if and_exit then exit 1 else reraise exn
106 | in
107 | Junit.Testsuite.add_testcases !testcases testsuite, exit
108 | ;;
109 |
--------------------------------------------------------------------------------
/alcotest/junit_alcotest.mli:
--------------------------------------------------------------------------------
1 | (** Interface to product JUnit reports for Alcotest
2 |
3 | It tries to provide a layer as thin as possible on top of Alcotest
4 | to allow to port existing test without writing a lot a boilerplate. *)
5 |
6 | (** [wrap_test handle_result test_cases] wraps test cases to create
7 | Junit testcases and pass them to [handle_result].
8 |
9 | Can be used with {!Alcotest.run} to create customized Junit testsuites if
10 | the output of {!run_and_report} is not as expected.
11 |
12 | @param classname
13 | will populate the 'classname' attribute
14 | for the test case. For best hierarchic rendering in Jenkins, it
15 | should contain a period. For example, "foo.bar.baz" will be rendered
16 | a package "foo.bar" that contains a class "baz", which contains the
17 | current test case and others. Defaults to the name of the test case. *)
18 | val wrap_test
19 | : ?classname:string
20 | -> (Junit.Testcase.t -> unit)
21 | -> unit Alcotest.test_case
22 | -> unit Alcotest.test_case
23 |
24 | (** [exit ()] exits with appropriate code if {!run_and_report}'s
25 | [and_exit] was [true] or raise {!Alcotest.Test_error} in case of
26 | error. *)
27 | type exit = unit -> unit
28 |
29 | (** [run_and_report name tests] is a wrapper around {!Alcotest.run} and {!wrap_test}.
30 | It runs the tests and creates a Junit testsuite from the results.
31 |
32 | As {!Alcotest.run} is always called with [and_exit = false] to be
33 | able to produce a report, the behavior is emulated by the returned
34 | {!exit} function.
35 |
36 | The optional argument [and_exit] controls what happens when the
37 | {!exit} function is called. By default, [and_exit] is set, which
38 | makes the function exit with [0] if everything is fine or [1] if
39 | there is an issue. If [and_exit] is [false], then the function
40 | raises [Test_error] on error.
41 |
42 | [?argv] is forwarded to {!run}. [?package] and [?timestamp] are
43 | forwarded to {!Junit.Testsuite.make}. *)
44 | val run_and_report
45 | : (?package:string
46 | -> ?timestamp:Ptime.t
47 | -> ?argv:string array
48 | -> string
49 | -> (string * unit Alcotest.test_case list) list
50 | -> Junit.Testsuite.t * exit)
51 | Alcotest.with_options
52 |
--------------------------------------------------------------------------------
/alcotest/test/alcotest_report.expected:
--------------------------------------------------------------------------------
1 | Invalid_argument("7")Alcotest assertion failure
2 | [1mFile "alcotest/junit_alcotest.ml", line 22, character 6:
3 | [0m[31mFAIL[0m string_of_int equals to '7'
4 |
5 | Expected: `[32m"7"[0m'
6 | Received: `[31m"8"[0m'
7 |
8 | Invalid_argument("7")Alcotest assertion failure
9 | [1mFile "alcotest/junit_alcotest.ml", line 22, character 6:
10 | [0m[31mFAIL[0m string_of_int equals to '7'
11 |
12 | Expected: `[32m"7"[0m'
13 | Received: `[31m"8"[0m'
14 |
15 |
16 |
--------------------------------------------------------------------------------
/alcotest/test/alcotest_report.ml:
--------------------------------------------------------------------------------
1 | module A = Alcotest
2 | module JA = Junit_alcotest
3 |
4 | module To_test = struct
5 | let capit letter = Astring.Char.Ascii.uppercase letter
6 | let plus int_list = List.fold_left (fun a b -> a + b) 0 int_list
7 | end
8 |
9 | let capit () = A.(check char) "Check A" 'A' (To_test.capit 'a')
10 | let plus () = A.(check int) "Sum equals to 7" 7 (To_test.plus [ 1; 1; 2; 3 ])
11 | let wrong_result () = A.(check string) "string_of_int equals to '7'" "7" (string_of_int 8)
12 |
13 | let raise_unexpected_exn () =
14 | A.(check int) "int_of_string equals to 7" 7 (invalid_arg "7")
15 | ;;
16 |
17 | let test_set =
18 | [ A.test_case "Test with unexpected exception" `Quick raise_unexpected_exn
19 | ; A.test_case "Capitalize" `Quick capit
20 | ; A.test_case "Add entries" `Slow plus
21 | ; A.test_case "Test with wrong result" `Quick wrong_result
22 | ; A.test_case "Test skipped" `Quick (fun () -> A.skip ())
23 | ]
24 | ;;
25 |
26 | let success_test_set =
27 | [ A.test_case "Capitalize" `Quick capit; A.test_case "Add entries" `Slow plus ]
28 | ;;
29 |
30 | let skipped_test_set =
31 | [ A.test_case "Skipped quick" `Quick (fun () -> A.skip ())
32 | ; A.test_case "Skipped slow" `Slow (fun () -> A.skip ())
33 | ]
34 | ;;
35 |
36 | let timestamp =
37 | match Ptime.of_date_time ((2013, 5, 24), ((10, 23, 58), 0)) with
38 | | Some t -> t
39 | | None -> assert false
40 | ;;
41 |
42 | let alcotest path =
43 | let package = "junit_alcotest" in
44 | let testsuite0, _ =
45 | JA.run_and_report
46 | ~package
47 | ~timestamp
48 | "Skip test suite"
49 | [ "Skipped tests", skipped_test_set ]
50 | in
51 | let testsuite1, _ =
52 | JA.run_and_report ~package ~timestamp "My first test" [ "Basic tests", test_set ]
53 | in
54 | let testsuite2, _ =
55 | JA.run_and_report ~package ~timestamp "My second test" [ "Basic tests", test_set ]
56 | in
57 | let testsuite3, exit =
58 | JA.run_and_report
59 | ~and_exit:false
60 | ~package
61 | ~timestamp
62 | "Success test suite"
63 | [ "Good tests", success_test_set ]
64 | in
65 | let report = Junit.make [ testsuite0; testsuite1; testsuite2; testsuite3 ] in
66 | (match path with
67 | | None ->
68 | let xml_report = Junit.to_xml report in
69 | Format.printf "%a\n" (Tyxml.Xml.pp ()) xml_report
70 | | Some path -> Junit.to_file report path);
71 | exit ()
72 | ;;
73 |
74 | let () =
75 | let path =
76 | try Some (Sys.getenv "REPORT_PATH") with
77 | | _ -> None
78 | in
79 | alcotest path
80 | ;;
81 |
--------------------------------------------------------------------------------
/alcotest/test/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name alcotest_report)
3 | (modules alcotest_report)
4 | (libraries junit junit_alcotest))
5 |
6 | (rule
7 | (targets alcotest_report.xml)
8 | (action
9 | (setenv
10 | REPORT_PATH
11 | %{targets}
12 | (run %{dep:alcotest_report.exe}))))
13 |
14 | (rule
15 | (alias runtest)
16 | (package junit_alcotest)
17 | (action
18 | (diff %{dep:alcotest_report.expected} %{dep:alcotest_report.xml}))
19 | (deps alcotest_report.exe))
20 |
--------------------------------------------------------------------------------
/doc/api.odocl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khady/ocaml-junit/9bebaba23bb930398fa1e0b513a95352da77cf2d/doc/api.odocl
--------------------------------------------------------------------------------
/doc/dev.odocl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khady/ocaml-junit/9bebaba23bb930398fa1e0b513a95352da77cf2d/doc/dev.odocl
--------------------------------------------------------------------------------
/doc/doc.odocl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khady/ocaml-junit/9bebaba23bb930398fa1e0b513a95352da77cf2d/doc/doc.odocl
--------------------------------------------------------------------------------
/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 3.0)
2 | (name junit)
3 |
--------------------------------------------------------------------------------
/junit.opam:
--------------------------------------------------------------------------------
1 | opam-version: "2.0"
2 | maintainer: "Louis Roché "
3 | authors: "Louis Roché "
4 | homepage: "https://github.com/Khady/ocaml-junit"
5 | bug-reports: "https://github.com/Khady/ocaml-junit/issues"
6 | license: "LGPL-3.0-or-later WITH OCaml-LGPL-linking-exception"
7 | dev-repo: "git+https://github.com/Khady/ocaml-junit.git"
8 | doc: "https://khady.github.io/ocaml-junit/"
9 | tags: ["junit" "jenkins"]
10 | depends: [
11 | "dune" {>= "3.0"}
12 | "ptime"
13 | "tyxml" {>= "4.0.0"}
14 | "odoc" {with-doc & >= "1.1.1"}
15 | "ocamlformat" {= "0.27.0" & with-dev-setup}
16 | ]
17 | build: [
18 | ["dune" "subst"] {dev}
19 | [
20 | "dune"
21 | "build"
22 | "-p"
23 | name
24 | "-j"
25 | jobs
26 | "@install"
27 | "@runtest" {with-test}
28 | "@doc" {with-doc}
29 | ]
30 | ]
31 | name: "junit"
32 | synopsis: "JUnit XML reports generation library"
33 | description: "JUnit XML reports generation library"
34 |
--------------------------------------------------------------------------------
/junit/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name junit)
3 | (public_name junit)
4 | (wrapped false)
5 | (synopsis "JUnit XML reports generation library")
6 | (libraries tyxml ptime ptime.clock.os))
7 |
--------------------------------------------------------------------------------
/junit/junit.ml:
--------------------------------------------------------------------------------
1 | module Property = struct
2 | type t =
3 | { name : string
4 | ; value : string
5 | }
6 |
7 | let make ~name ~value = { name; value }
8 | end
9 |
10 | module Testcase = struct
11 | type error = Junit_xml.error =
12 | { message : string option
13 | ; typ : string
14 | ; description : string
15 | }
16 |
17 | type failure = Junit_xml.failure =
18 | { message : string option
19 | ; typ : string
20 | ; description : string
21 | }
22 |
23 | type result = Junit_xml.result =
24 | | Error of error
25 | | Failure of failure
26 | | Pass
27 | | Skipped
28 |
29 | type t =
30 | { name : string
31 | ; classname : string
32 | ; time : float
33 | ; result : result
34 | }
35 |
36 | let make ~name ~classname ~time result = { name; classname; time; result }
37 |
38 | let error ?message ~typ ~name ~classname ~time description =
39 | let result = Error { message; typ; description } in
40 | make ~name ~classname ~time result
41 | ;;
42 |
43 | let failure ?message ~typ ~name ~classname ~time description =
44 | let result = Failure { message; typ; description } in
45 | make ~name ~classname ~time result
46 | ;;
47 |
48 | let skipped ~name ~classname ~time = make ~name ~classname ~time Skipped
49 | let pass ~name ~classname ~time = make ~name ~classname ~time Pass
50 | end
51 |
52 | module Testsuite = struct
53 | type t =
54 | { package : string
55 | ; id : int
56 | ; name : string
57 | ; timestamp : Ptime.t
58 | ; hostname : string
59 | ; tests : int
60 | ; failures : int
61 | ; errors : int
62 | ; skipped : int
63 | ; time : float
64 | ; system_out : string option
65 | ; system_err : string option
66 | ; properties : Property.t list
67 | ; testcases : Testcase.t list
68 | }
69 |
70 | let make ?package ?timestamp ?(hostname = "localhost") ?system_out ?system_err ~name () =
71 | let package =
72 | match package with
73 | | None -> name
74 | | Some p -> p
75 | in
76 | let timestamp =
77 | match timestamp with
78 | | None -> Ptime_clock.now ()
79 | | Some t -> t
80 | in
81 | { package
82 | ; id = 0
83 | ; name
84 | ; timestamp
85 | ; hostname
86 | ; tests = 0
87 | ; failures = 0
88 | ; errors = 0
89 | ; skipped = 0
90 | ; time = 0.
91 | ; system_out
92 | ; system_err
93 | ; properties = []
94 | ; testcases = []
95 | }
96 | ;;
97 |
98 | let add_testcase testcase t =
99 | let t =
100 | { t with
101 | tests = t.tests + 1
102 | ; time = t.time +. testcase.Testcase.time
103 | ; testcases = testcase :: t.testcases
104 | }
105 | in
106 | match testcase.Testcase.result with
107 | | Testcase.Pass -> t
108 | | Testcase.Skipped -> { t with skipped = t.skipped + 1 }
109 | | Testcase.Error _ -> { t with errors = t.errors + 1 }
110 | | Testcase.Failure _ -> { t with failures = t.failures + 1 }
111 | ;;
112 |
113 | let add_testcases testcases t =
114 | List.fold_left (fun t tc -> add_testcase tc t) t testcases
115 | ;;
116 |
117 | let add_property properties t = { t with properties = properties :: t.properties }
118 |
119 | let add_properties properties t =
120 | List.fold_left (fun t tc -> add_property tc t) t properties
121 | ;;
122 | end
123 |
124 | type t =
125 | { next_id : int
126 | ; testsuites : Testsuite.t list
127 | }
128 |
129 | let make testsuites =
130 | let testsuites = List.mapi (fun i t -> Testsuite.{ t with id = i }) testsuites in
131 | let length = List.length testsuites in
132 | { next_id = length; testsuites }
133 | ;;
134 |
135 | let add_testsuite testsuite t =
136 | let ts = Testsuite.{ testsuite with id = t.next_id } in
137 | { next_id = succ t.next_id; testsuites = ts :: t.testsuites }
138 | ;;
139 |
140 | let to_xml (t : t) =
141 | let testsuites =
142 | List.map
143 | (fun t ->
144 | let properties =
145 | let open Property in
146 | List.map
147 | (fun p -> Junit_xml.property ~name:p.name ~value:p.value)
148 | t.Testsuite.properties
149 | in
150 | let testcases =
151 | let open Testcase in
152 | List.map
153 | (fun p ->
154 | Junit_xml.testcase
155 | ~name:p.name
156 | ~classname:p.classname
157 | ~time:p.time
158 | p.result)
159 | t.Testsuite.testcases
160 | in
161 | let open Testsuite in
162 | Junit_xml.testsuite
163 | ?system_out:t.system_out
164 | ?system_err:t.system_err
165 | ~package:t.package
166 | ~id:t.id
167 | ~name:t.name
168 | ~timestamp:(Junit_xml.timestamp t.timestamp)
169 | ~hostname:t.hostname
170 | ~tests:t.tests
171 | ~failures:t.failures
172 | ~errors:t.errors
173 | ~skipped:t.skipped
174 | ~time:t.time
175 | properties
176 | testcases)
177 | t.testsuites
178 | in
179 | Junit_xml.to_xml testsuites
180 | ;;
181 |
182 | let to_file (t : t) filename =
183 | let xml_report = to_xml t in
184 | let oc = open_out filename in
185 | let fmt = Format.formatter_of_out_channel oc in
186 | Format.fprintf fmt "@[%a@]@." (Tyxml.Xml.pp ()) xml_report;
187 | close_out oc;
188 | ()
189 | ;;
190 |
--------------------------------------------------------------------------------
/junit/junit.mli:
--------------------------------------------------------------------------------
1 | (** High level interface to produce JUnit reports. *)
2 |
3 | (** This module defines functions to create JUnit reports and export
4 | them to XML. This XML is supposed to be accepted by Jenkins. *)
5 |
6 | module Property : sig
7 | (** Properties (e.g., environment settings) set during test execution. *)
8 |
9 | type t
10 |
11 | val make : name:string -> value:string -> t
12 | end
13 |
14 | module Testcase : sig
15 | type t
16 |
17 | (** [error ?message ~typ ~name ~classname ~time description] creates
18 | an error element.
19 |
20 | Indicates that the test errored. An errored test is one that had an
21 | unanticipated problem. e.g., an unchecked throwable; or a
22 | problem with the implementation of the test. Contains as a text
23 | node relevant data for the error, e.g., a stack trace.
24 |
25 | @param message
26 | The error message. e.g., if a java exception is
27 | thrown, the return value of getMessage().
28 |
29 | @param typ
30 | The type of error that occured. e.g., if a java
31 | execption is thrown the full class name of the exception.
32 |
33 | @param description Description of the error.
34 |
35 | @param name Name of the test method.
36 |
37 | @param classname Full class name for the class the test method is
38 | in.
39 |
40 | @param time Time taken (in seconds) to execute the test. *)
41 | val error
42 | : ?message:string
43 | -> typ:string
44 | -> name:string
45 | -> classname:string
46 | -> time:float
47 | -> string
48 | -> t
49 |
50 | (** [failure ?message ~typ ~name ~classname ~time description] creates
51 | a failure element.
52 |
53 | Indicates that the test failed. A failure is a test which the code has
54 | explicitly failed by using the mechanisms for that
55 | purpose. e.g., via an assertEquals. Contains as a text node
56 | relevant data for the failure, e.g., a stack trace.
57 |
58 | @param message The message specified in the assert.
59 |
60 | @param typ The type of the assert.
61 |
62 | @param description Description of the failure.
63 |
64 | @param name Name of the test method.
65 |
66 | @param classname Full class name for the class the test method is
67 | in.
68 |
69 | @param time Time taken (in seconds) to execute the test. *)
70 | val failure
71 | : ?message:string
72 | -> typ:string
73 | -> name:string
74 | -> classname:string
75 | -> time:float
76 | -> string
77 | -> t
78 |
79 | (** [skipped ~name ~classname ~time] creates a skipped element.
80 |
81 | Indicates that the test has not been launched.
82 |
83 | @param name Name of the test method.
84 |
85 | @param classname Full class name for the class the test method is
86 | in.
87 |
88 | @param time Time taken (in seconds) to execute the test. *)
89 | val skipped : name:string -> classname:string -> time:float -> t
90 |
91 | (** [pass ~name ~classname ~time] creates a pass element.
92 |
93 | Indicates that the test is a success.
94 |
95 | @param name Name of the test method.
96 |
97 | @param classname Full class name for the class the test method is
98 | in.
99 |
100 | @param time Time taken (in seconds) to execute the test. *)
101 | val pass : name:string -> classname:string -> time:float -> t
102 | end
103 |
104 | module Testsuite : sig
105 | (** Contains the results of executing a testsuite. *)
106 |
107 | type t
108 |
109 | (** [make ?package ?timestamp ?hostname ?system_out ?system_err
110 | ~name ()] creates a testsuite.
111 |
112 | Attributes
113 |
114 | @param package Derived from the testsuite name in the
115 | non-aggregated documents.
116 |
117 | @param timestamp
118 | When the test was executed. Timezone may not be
119 | specified. Uses the current time by default.
120 |
121 | @param hostname Host on which the tests were executed. Uses
122 | [localhost] by default.
123 |
124 | @param system_out Data that was written to standard out while
125 | the test was executed.
126 |
127 | @param system_err
128 | Data that was written to standard error while
129 | the test was executed.
130 |
131 | @param name
132 | Full class name of the test for non-aggregated
133 | testsuite documents. Class name without the package for
134 | aggregated testsuites documents. *)
135 | val make
136 | : ?package:string
137 | -> ?timestamp:Ptime.t
138 | -> ?hostname:string
139 | -> ?system_out:string
140 | -> ?system_err:string
141 | -> name:string
142 | -> unit
143 | -> t
144 |
145 | val add_testcases : Testcase.t list -> t -> t
146 | val add_properties : Property.t list -> t -> t
147 | end
148 |
149 | (** Contains an aggregation of testsuite results. *)
150 | type t
151 |
152 | val make : Testsuite.t list -> t
153 | val add_testsuite : Testsuite.t -> t -> t
154 | val to_xml : t -> Tyxml.Xml.elt
155 | val to_file : t -> string -> unit
156 |
--------------------------------------------------------------------------------
/junit/junit_xml.ml:
--------------------------------------------------------------------------------
1 | open Tyxml.Xml
2 |
3 | type token = string
4 | type timestamp = string
5 |
6 | let timestamp time =
7 | let (y, m, d), ((hh, ss, mm), _) = Ptime.to_date_time time in
8 | Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02d" y m d hh ss mm
9 | ;;
10 |
11 | type property =
12 | { name : token
13 | ; value : string
14 | }
15 |
16 | type properties = property list
17 |
18 | let property ~name ~value = { name; value }
19 |
20 | let property_to_xml property =
21 | let name = string_attrib "name" property.name in
22 | let value = string_attrib "value" property.value in
23 | node "property" ~a:[ name; value ] []
24 | ;;
25 |
26 | let properties_to_xml properties = node "properties" (List.map property_to_xml properties)
27 |
28 | type error =
29 | { message : string option
30 | ; typ : string
31 | ; description : string
32 | }
33 |
34 | let error ?message ~typ description : error = { message; typ; description }
35 |
36 | let error_to_xml (error : error) =
37 | let typ = string_attrib "type" error.typ in
38 | let attributes = [ typ ] in
39 | let attributes =
40 | match error.message with
41 | | None -> attributes
42 | | Some m ->
43 | let message = string_attrib "message" m in
44 | message :: attributes
45 | in
46 | let description = pcdata error.description in
47 | node "error" ~a:attributes [ description ]
48 | ;;
49 |
50 | type failure =
51 | { message : string option
52 | ; typ : string
53 | ; description : string
54 | }
55 |
56 | let failure ?message ~typ description : failure = { message; typ; description }
57 |
58 | let failure_to_xml (failure : failure) =
59 | let typ = string_attrib "type" failure.typ in
60 | let attributes = [ typ ] in
61 | let attributes =
62 | match failure.message with
63 | | None -> attributes
64 | | Some m ->
65 | let message = string_attrib "message" m in
66 | message :: attributes
67 | in
68 | let description = pcdata failure.description in
69 | node "failure" ~a:attributes [ description ]
70 | ;;
71 |
72 | type result =
73 | | Error of error
74 | | Failure of failure
75 | | Pass
76 | | Skipped
77 |
78 | let result_to_xml : result -> Tyxml.Xml.elt = function
79 | | Error e -> error_to_xml e
80 | | Failure f -> failure_to_xml f
81 | | Pass -> Tyxml.Xml.empty ()
82 | | Skipped -> node "skipped" []
83 | ;;
84 |
85 | type testcase =
86 | { name : string
87 | ; classname : token
88 | ; time : float
89 | ; result : result
90 | }
91 |
92 | type testcases = testcase list
93 |
94 | let testcase ~name ~classname ~time result = { name; classname; time; result }
95 |
96 | let testcase_to_xml (testcase : testcase) =
97 | let name = string_attrib "name" testcase.name in
98 | let classname = string_attrib "classname" testcase.classname in
99 | let time = float_attrib "time" testcase.time in
100 | let result = result_to_xml testcase.result in
101 | node "testcase" ~a:[ name; classname; time ] [ result ]
102 | ;;
103 |
104 | type testsuite =
105 | { package : token
106 | ; id : int
107 | ; name : token
108 | ; timestamp : timestamp
109 | ; hostname : token
110 | ; tests : int
111 | ; failures : int
112 | ; errors : int
113 | ; skipped : int
114 | ; time : float
115 | ; properties : properties
116 | ; testcases : testcases
117 | ; system_out : string option
118 | ; system_err : string option
119 | }
120 |
121 | type testsuites = testsuite list
122 |
123 | let testsuite
124 | ?system_out
125 | ?system_err
126 | ~package
127 | ~id
128 | ~name
129 | ~timestamp
130 | ~hostname
131 | ~tests
132 | ~failures
133 | ~errors
134 | ~skipped
135 | ~time
136 | properties
137 | testcases
138 | =
139 | { package
140 | ; id
141 | ; name
142 | ; timestamp
143 | ; hostname
144 | ; tests
145 | ; failures
146 | ; errors
147 | ; skipped
148 | ; time
149 | ; properties
150 | ; testcases
151 | ; system_out
152 | ; system_err
153 | }
154 | ;;
155 |
156 | let testsuite_to_xml testsuite =
157 | let package = string_attrib "package" testsuite.package in
158 | let id = int_attrib "id" testsuite.id in
159 | let name = string_attrib "name" testsuite.name in
160 | let timestamp = string_attrib "timestamp" testsuite.timestamp in
161 | let hostname = string_attrib "hostname" testsuite.hostname in
162 | let tests = int_attrib "tests" testsuite.tests in
163 | let failures = int_attrib "failures" testsuite.failures in
164 | let errors = int_attrib "errors" testsuite.errors in
165 | let skipped = int_attrib "skipped" testsuite.skipped in
166 | let time = float_attrib "time" testsuite.time in
167 | let attributes =
168 | [ package; id; name; timestamp; hostname; tests; failures; errors; skipped; time ]
169 | in
170 | let system_out =
171 | match testsuite.system_out with
172 | | None -> empty ()
173 | | Some so -> node "system_out" [ pcdata so ]
174 | in
175 | let system_err =
176 | match testsuite.system_err with
177 | | None -> empty ()
178 | | Some se -> node "system_err" [ pcdata se ]
179 | in
180 | let properties = properties_to_xml testsuite.properties in
181 | let testcases = List.map testcase_to_xml testsuite.testcases in
182 | node "testsuite" ~a:attributes (properties :: system_out :: system_err :: testcases)
183 | ;;
184 |
185 | let to_xml testsuites =
186 | let elements = List.map testsuite_to_xml testsuites in
187 | node "testsuites" elements
188 | ;;
189 |
--------------------------------------------------------------------------------
/junit/junit_xml.mli:
--------------------------------------------------------------------------------
1 | (** Low level interface to build XML elements. *)
2 |
3 | (** This module defines basic data types for data, attributes and
4 | element occuring in JUnit reports.
5 |
6 | It is based on the XSD provided in
7 | {{:https://github.com/windyroad/JUnit-Schema} JUnit-schema} git
8 | repository.
9 |
10 | Those are low level functions. Values like [id], [failures] or
11 | [tests] will not be checked.
12 |
13 | It allows you to build a report by hand if the facilities that are
14 | offered by {!module:Junit} do not suit your needs. *)
15 |
16 | (** {2 Categories of elements and attributes} *)
17 |
18 | (** This part defines the categories of elements and attributes. *)
19 |
20 | (** {3 Attributes} *)
21 |
22 | (** https://www.w3.org/TR/xmlschema-2/#token
23 |
24 | [Definition:] token represents tokenized strings. The ·value space· of
25 | token is the set of strings that do not contain the carriage return
26 | (#xD), line feed (#xA) nor tab (#x9) characters, that have no
27 | leading or trailing spaces (#x20) and that have no internal
28 | sequences of two or more spaces. The ·lexical space· of token is
29 | the set of strings that do not contain the carriage return (#xD),
30 | line feed (#xA) nor tab (#x9) characters, that have no leading or
31 | trailing spaces (#x20) and that have no internal sequences of two
32 | or more spaces. The ·base type· of token is normalizedString. *)
33 | type token = string
34 |
35 | type timestamp
36 |
37 | val timestamp : Ptime.t -> timestamp
38 |
39 | (** {3 Elements} *)
40 |
41 | (** {4 Properties} *)
42 |
43 | type property
44 |
45 | (** Properties (e.g., environment settings) set during test execution. *)
46 | type properties = property list
47 |
48 | val property : name:token -> value:string -> property
49 |
50 | (** Builds an XML element from a property. *)
51 | val property_to_xml : property -> Tyxml.Xml.elt
52 |
53 | (** {4 Testcases} *)
54 |
55 | (** Indicates that the test errored. An errored test is one that had
56 | an unanticipated problem. e.g., an unchecked throwable; or a problem
57 | with the implementation of the test. Contains as a text node
58 | relevant data for the error, e.g., a stack trace. *)
59 | type error =
60 | { message : string option
61 | ; typ : string
62 | ; description : string
63 | }
64 |
65 | (** [error ?message ~typ description] creates an error element.
66 |
67 | @param message
68 | The error message. e.g., if a java exception is
69 | thrown, the return value of getMessage().
70 |
71 | @param typ
72 | The type of error that occured. e.g., if a java
73 | execption is thrown the full class name of the exception.
74 |
75 | @param description Description of the error. *)
76 | val error : ?message:string -> typ:string -> string -> error
77 |
78 | (** Builds an XML element from a error. *)
79 | val error_to_xml : error -> Tyxml.Xml.elt
80 |
81 | (** Indicates that the test failed. A failure is a test which the code
82 | has explicitly failed by using the mechanisms for that purpose. e.g.,
83 | via an assertEquals. Contains as a text node relevant data for the
84 | failure, e.g., a stack trace. *)
85 | type failure =
86 | { message : string option
87 | ; typ : string
88 | ; description : string
89 | }
90 |
91 | (** [failure ?message ~typ description] creates a failure element.
92 |
93 | @param message The message specified in the assert.
94 | @param typ The type of the assert.
95 | @param description Description of the failure. *)
96 | val failure : ?message:string -> typ:string -> string -> failure
97 |
98 | (** Builds an XML element from a failure. *)
99 | val failure_to_xml : failure -> Tyxml.Xml.elt
100 |
101 | type result =
102 | | Error of error
103 | | Failure of failure
104 | | Pass
105 | | Skipped (** Not part of the spec, but available in jenkins. *)
106 |
107 | (** Builds an XML element from a result. *)
108 | val result_to_xml : result -> Tyxml.Xml.elt
109 |
110 | type testcase
111 | type testcases = testcase list
112 |
113 | (** Creates a testcase.
114 |
115 | @param name Name of the test method.
116 |
117 | @param classname Full class name for the class the test method is
118 | in.
119 |
120 | @param time Time taken (in seconds) to execute the test.
121 |
122 | @param result Result of the test. *)
123 | val testcase : name:token -> classname:token -> time:float -> result -> testcase
124 |
125 | (** Builds an XML element from a testcase. *)
126 | val testcase_to_xml : testcase -> Tyxml.Xml.elt
127 |
128 | (** {4 Testsuites} *)
129 |
130 | (** Contains the results of executing a testsuite. *)
131 | type testsuite
132 |
133 | (** Contains an aggregation of testsuite results. *)
134 | type testsuites = testsuite list
135 |
136 | (** Creates a testsuite.
137 |
138 | Attributes
139 |
140 | @param package Derived from the testsuite name in the non-aggregated
141 | documents.
142 |
143 | @param id
144 | Starts at 0 for the first testsuite and is incremented
145 | by 1 for each following testsuite.
146 |
147 | @param name
148 | Full class name of the test for non-aggregated
149 | testsuite documents. Class name without the package for aggregated
150 | testsuites documents.
151 |
152 | @param timestamp When the test was executed. Timezone may not be
153 | specified.
154 |
155 | @param hostname
156 | Host on which the tests were executed. 'localhost'
157 | should be used if the hostname cannot be determined.
158 |
159 | @param tests
160 | The total number of tests in the suite.The total
161 | number of tests in the suite.
162 |
163 | @param failures
164 | The total number of tests in the suite that
165 | failed. A failure is a test which the code has explicitly failed
166 | by using the mechanisms for that purpose. e.g., via an
167 | assertEquals.
168 |
169 | @param errors
170 | The total number of tests in the suite that
171 | errored. An errored test is one that had an unanticipated
172 | problem. e.g., an unchecked throwable; or a problem with the
173 | implementation of the test.
174 |
175 | @param skipped The total number of tests in the suite that
176 | were skipped. A skipped test is one that was not run because
177 | the conditions for running it were not met.
178 |
179 | @param time Time taken (in seconds) to execute the tests in the
180 | suite.
181 |
182 | Elements
183 |
184 | @param properties Properties (e.g., environment settings) set
185 | during test execution.
186 |
187 | @param testcases List of test executed.
188 |
189 | @param system_out Data that was written to standard out while the
190 | test was executed.
191 |
192 | @param system_err Data that was written to standard error while
193 | the test was executed. *)
194 | val testsuite
195 | : ?system_out:string
196 | -> ?system_err:string
197 | -> package:token
198 | -> id:int
199 | -> name:token
200 | -> timestamp:timestamp
201 | -> hostname:token
202 | -> tests:int
203 | -> failures:int
204 | -> errors:int
205 | -> skipped:int
206 | -> time:float
207 | -> properties
208 | -> testcases
209 | -> testsuite
210 |
211 | (** Builds an XML element from a testsuite. *)
212 | val testsuite_to_xml : testsuite -> Tyxml.Xml.elt
213 |
214 | (** Builds an XML element from a list of testsuites. *)
215 | val to_xml : testsuites -> Tyxml.Xml.elt
216 |
--------------------------------------------------------------------------------
/junit/test/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name simple)
3 | (modules simple)
4 | (libraries junit))
5 |
6 | (rule
7 | (targets simple.xml)
8 | (action
9 | (run %{dep:simple.exe} %{targets})))
10 |
11 | (rule
12 | (alias runtest)
13 | (deps simple.exe)
14 | (package junit)
15 | (action
16 | (diff %{dep:simple.expected} %{dep:simple.xml})))
17 |
--------------------------------------------------------------------------------
/junit/test/simple.expected:
--------------------------------------------------------------------------------
1 | Assertion failed
2 |
--------------------------------------------------------------------------------
/junit/test/simple.ml:
--------------------------------------------------------------------------------
1 | (** Encode this example (from http://help.catchsoftware.com/display/ET/JUnit+Format):
2 |
3 |
4 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
16 | Assertion failed
17 |
18 |
21 |
22 |
23 |
26 |
27 | *)
28 |
29 | let timestamp =
30 | match Ptime.of_date_time ((2013, 5, 24), ((10, 23, 58), 0)) with
31 | | Some t -> t
32 | | None -> assert false
33 | ;;
34 |
35 | let simple path =
36 | let junitXmlReporter = Junit.Testsuite.make ~timestamp ~name:"JUnitXmlReporter" () in
37 | let junitXmlReportConstructor =
38 | let properties =
39 | [ Junit.Property.make ~name:"java.vendor" ~value:"Sun Microsystems Inc."
40 | ; Junit.Property.make ~name:"compiler.debug" ~value:"on"
41 | ; Junit.Property.make ~name:"project.jdk.classpath" ~value:"jdk.classpath.1.6"
42 | ]
43 | in
44 | let testcases =
45 | [ Junit.Testcase.failure
46 | ~name:"should default path to an empty string"
47 | ~classname:"JUnitXmlReporter.constructor"
48 | ~time:0.006
49 | ~message:"test failure"
50 | ~typ:"not equal"
51 | "Assertion failed"
52 | ; Junit.Testcase.skipped
53 | ~name:"should default consolidate to true"
54 | ~classname:"JUnitXmlReporter.constructor"
55 | ~time:0.
56 | ; Junit.Testcase.pass
57 | ~name:"should default useDotNotation to true"
58 | ~classname:"JUnitXmlReporter.constructor"
59 | ~time:0.
60 | ]
61 | in
62 | Junit.Testsuite.make ~timestamp ~name:"JUnitXmlReporter.constructor" ()
63 | |> Junit.Testsuite.add_testcases testcases
64 | |> Junit.Testsuite.add_properties properties
65 | in
66 | let report = Junit.make [ junitXmlReporter; junitXmlReportConstructor ] in
67 | match path with
68 | | None ->
69 | let xml_report = Junit.to_xml report in
70 | Format.printf "%a\n" (Tyxml.Xml.pp ()) xml_report
71 | | Some path -> Junit.to_file report path
72 | ;;
73 |
74 | let () =
75 | let path = if Array.length Sys.argv > 1 then Some Sys.argv.(1) else None in
76 | simple path
77 | ;;
78 |
--------------------------------------------------------------------------------
/junit_alcotest.opam:
--------------------------------------------------------------------------------
1 | opam-version: "2.0"
2 | maintainer: "Louis Roché "
3 | authors: ["Louis Roché "]
4 | homepage: "https://github.com/Khady/ocaml-junit"
5 | bug-reports: "https://github.com/Khady/ocaml-junit/issues"
6 | license: "LGPL-3.0-or-later WITH OCaml-LGPL-linking-exception"
7 | dev-repo: "git+https://github.com/Khady/ocaml-junit.git"
8 | doc: "https://khady.github.io/ocaml-junit/"
9 | tags: ["junit" "jenkins" "alcotest"]
10 | depends: [
11 | "dune" {>= "3.0"}
12 | "odoc" {with-doc & >= "1.1.1"}
13 | "alcotest" {>= "1.9.0"}
14 | "junit" {= version}
15 | "ocamlformat" {= "0.27.0" & with-dev-setup}
16 | ]
17 | build: [
18 | ["dune" "subst"] {dev}
19 | [
20 | "dune"
21 | "build"
22 | "-p"
23 | name
24 | "-j"
25 | jobs
26 | "@install"
27 | "@runtest" {with-test}
28 | "@doc" {with-doc}
29 | ]
30 | ]
31 | name: "junit_alcotest"
32 | synopsis: "JUnit XML reports generation for alcotest tests"
33 | description: "JUnit XML reports generation for alcotest tests"
34 |
--------------------------------------------------------------------------------
/junit_ounit.opam:
--------------------------------------------------------------------------------
1 | opam-version: "2.0"
2 | maintainer: "Louis Roché "
3 | authors: ["Louis Roché " "Simon Cruanes "]
4 | homepage: "https://github.com/Khady/ocaml-junit"
5 | bug-reports: "https://github.com/Khady/ocaml-junit/issues"
6 | license: "LGPL-3.0-or-later WITH OCaml-LGPL-linking-exception"
7 | dev-repo: "git+https://github.com/Khady/ocaml-junit.git"
8 | doc: "https://khady.github.io/ocaml-junit/"
9 | tags: ["junit" "jenkins" "ounit"]
10 | depends: [
11 | "dune" {>= "3.0"}
12 | "odoc" {with-doc & >= "1.1.1"}
13 | "ounit2"
14 | "junit" {= version}
15 | "ocamlformat" {= "0.27.0" & with-dev-setup}
16 | ]
17 | build: [
18 | ["dune" "subst"] {dev}
19 | [
20 | "dune"
21 | "build"
22 | "-p"
23 | name
24 | "-j"
25 | jobs
26 | "@install"
27 | "@runtest" {with-test}
28 | "@doc" {with-doc}
29 | ]
30 | ]
31 | name: "junit_ounit"
32 | synopsis: "JUnit XML reports generation for OUnit tests"
33 | description: "JUnit XML reports generation for OUnit tests"
34 |
--------------------------------------------------------------------------------
/ounit/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name junit_ounit)
3 | (public_name junit_ounit)
4 | (wrapped false)
5 | (synopsis "JUnit XML reports generation for OUnit tests")
6 | (libraries junit ounit2))
7 |
--------------------------------------------------------------------------------
/ounit/junit_ounit.ml:
--------------------------------------------------------------------------------
1 | (** Interface from OUnit result to JUnit reports *)
2 |
3 | module O = OUnit
4 | module J = Junit
5 |
6 | let of_result o =
7 | let time = 0. in
8 | let classname = "" in
9 | let typ = "" in
10 | match o with
11 | | O.RError (path, msg) ->
12 | J.Testcase.error ~typ ~classname ~time ~name:(O.string_of_path path) ~message:msg ""
13 | | O.RSuccess path -> J.Testcase.pass ~classname ~time ~name:(O.string_of_path path)
14 | | O.RFailure (path, msg) ->
15 | J.Testcase.failure ~typ ~classname ~time ~message:msg ~name:(O.string_of_path path) ""
16 | | O.RSkip (path, _msg) ->
17 | J.Testcase.skipped ~classname ~time ~name:(O.string_of_path path)
18 | | O.RTodo (path, _msg) ->
19 | J.Testcase.skipped ~classname ~time ~name:(O.string_of_path path ^ "(todo)")
20 | ;;
21 |
22 | let of_results ~name l =
23 | let l = List.map of_result l in
24 | let suite = J.Testsuite.make ~name () in
25 | J.Testsuite.add_testcases l suite
26 | ;;
27 |
28 | let to_file ~name file l =
29 | let suite = of_results ~name l in
30 | let report = Junit.make [ suite ] in
31 | let xml_report = Junit.to_xml report in
32 | let oc = open_out file in
33 | let fmt = Format.formatter_of_out_channel oc in
34 | Format.fprintf fmt "@[%a@]@." (Tyxml.Xml.pp ()) xml_report;
35 | close_out oc;
36 | ()
37 | ;;
38 |
--------------------------------------------------------------------------------
/ounit/junit_ounit.mli:
--------------------------------------------------------------------------------
1 | (** Interface from OUnit result to JUnit reports *)
2 |
3 | val of_result : OUnit.test_result -> Junit.Testcase.t
4 |
5 | (** [of_results ~name l] converts the list of results [l] into a
6 | Junit testsuite named [name]. *)
7 | val of_results : name:string -> OUnit.test_results -> Junit.Testsuite.t
8 |
9 | (** Shortcut: converts the test results to a Junit testsuite, and dump
10 | it into the given file as XML. *)
11 | val to_file : name:string -> string -> OUnit.test_results -> unit
12 |
--------------------------------------------------------------------------------
/schemes/gist.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | Jenkins xUnit test result schema.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Contains an aggregation of testsuite results
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Derived from testsuite/@name in the non-aggregated documents
29 |
30 |
31 |
32 |
33 | Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Contains the results of exexuting a testsuite
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace
54 |
55 |
56 |
57 |
58 |
59 |
60 | The error message. e.g., if a java exception is thrown, the return value of getMessage()
61 |
62 |
63 |
64 |
65 | The type of error that occured. e.g., if a java execption is thrown the full class name of the exception.
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace
75 |
76 |
77 |
78 |
79 |
80 |
81 | The message specified in the assert
82 |
83 |
84 |
85 |
86 | The type of the assert.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | Indicates that the test was skipped. A skipped test is a test which was ignored using framework mechanisms. e.g., @Ignore annotation.
96 |
97 |
98 |
99 |
100 |
101 |
102 | Skip type.
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | Name of the test method
113 |
114 |
115 |
116 |
117 | Full class name for the class the test method is in.
118 |
119 |
120 |
121 |
122 | Time taken (in seconds) to execute the test
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | when the test was executed. Timezone may not be specified.
141 |
142 |
143 |
144 |
145 | Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined.
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | The total number of tests in the suite
156 |
157 |
158 |
159 |
160 | The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals
161 |
162 |
163 |
164 |
165 | The total number of tests in the suite that errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test.
166 |
167 |
168 |
169 |
170 | The total number of tests in the suite that skipped. A skipped test is a test which was ignored using framework mechanisms. e.g., @Ignore annotation.
171 |
172 |
173 |
174 |
175 | Time taken (in seconds) to execute the tests in the suite
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/schemes/jenkins.xsd:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/schemes/junit-schema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | JUnit test result schema for the Apache Ant JUnit and JUnitReport tasks
8 | Copyright © 2011, Windy Road Technology Pty. Limited
9 | The Apache Ant JUnit XML Schema is distributed under the terms of the Apache License Version 2.0 http://www.apache.org/licenses/
10 | Permission to waive conditions of this license may be requested from Windy Road Support (http://windyroad.org/support).
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Contains an aggregation of testsuite results
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Derived from testsuite/@name in the non-aggregated documents
31 |
32 |
33 |
34 |
35 | Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Contains the results of executing a testsuite
48 |
49 |
50 |
51 |
52 | Properties (e.g., environment settings) set during test execution
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace
77 |
78 |
79 |
80 |
81 |
82 |
83 | The error message. e.g., if a java exception is thrown, the return value of getMessage()
84 |
85 |
86 |
87 |
88 | The type of error that occured. e.g., if a java execption is thrown the full class name of the exception.
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace
98 |
99 |
100 |
101 |
102 |
103 |
104 | The message specified in the assert
105 |
106 |
107 |
108 |
109 | The type of the assert.
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | Name of the test method
120 |
121 |
122 |
123 |
124 | Full class name for the class the test method is in.
125 |
126 |
127 |
128 |
129 | Time taken (in seconds) to execute the test
130 |
131 |
132 |
133 |
134 |
135 |
136 | Data that was written to standard out while the test was executed
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | Data that was written to standard error while the test was executed
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | when the test was executed. Timezone may not be specified.
168 |
169 |
170 |
171 |
172 | Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined.
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | The total number of tests in the suite
183 |
184 |
185 |
186 |
187 | The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals
188 |
189 |
190 |
191 |
192 | The total number of tests in the suite that errorrd. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test.
193 |
194 |
195 |
196 |
197 | Time taken (in seconds) to execute the tests in the suite
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
--------------------------------------------------------------------------------
/schemes/windyroad.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | JUnit test result schema for the Apache Ant JUnit and JUnitReport tasks
8 | Copyright © 2011, Windy Road Technology Pty. Limited
9 | The Apache Ant JUnit XML Schema is distributed under the terms of the GNU Lesser General Public License (LGPL) http://www.gnu.org/licenses/lgpl.html
10 | Permission to waive conditions of this license may be requested from Windy Road Support (http://windyroad.org/support).
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Contains an aggregation of testsuite results
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Derived from testsuite/@name in the non-aggregated documents
31 |
32 |
33 |
34 |
35 | Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Contains the results of exexuting a testsuite
48 |
49 |
50 |
51 |
52 | Properties (e.g., environment settings) set during test execution
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace
77 |
78 |
79 |
80 |
81 |
82 |
83 | The error message. e.g., if a java exception is thrown, the return value of getMessage()
84 |
85 |
86 |
87 |
88 | The type of error that occured. e.g., if a java execption is thrown the full class name of the exception.
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace
98 |
99 |
100 |
101 |
102 |
103 |
104 | The message specified in the assert
105 |
106 |
107 |
108 |
109 | The type of the assert.
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | Name of the test method
120 |
121 |
122 |
123 |
124 | Full class name for the class the test method is in.
125 |
126 |
127 |
128 |
129 | Time taken (in seconds) to execute the test
130 |
131 |
132 |
133 |
134 |
135 |
136 | Data that was written to standard out while the test was executed
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | Data that was written to standard error while the test was executed
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | when the test was executed. Timezone may not be specified.
168 |
169 |
170 |
171 |
172 | Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined.
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | The total number of tests in the suite
183 |
184 |
185 |
186 |
187 | The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals
188 |
189 |
190 |
191 |
192 | The total number of tests in the suite that errorrd. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test.
193 |
194 |
195 |
196 |
197 | Time taken (in seconds) to execute the tests in the suite
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------