Đặc tả định dạng XML của JUnit mà Hudson hỗ trợ là gì?


183

Tôi có Hudson là máy chủ tích hợp liên tục và tôi muốn sử dụng tùy chọn 'Xuất bản báo cáo kết quả kiểm tra JUnit'. Nhưng tôi không sử dụng các công cụ xUnit để kiểm tra, thay vào đó tôi có các kịch bản shell chạy thử nghiệm và trả về kết quả ở định dạng đơn giản. Tôi đang suy nghĩ để tạo ra một kịch bản chuyển đổi các kết quả này sang định dạng JUnit. Vì vậy, tôi thú vị làm thế nào các tập tin JUnit phải nhìn?


Bất kỳ lý do để không sử dụng JUnit? Các thử nghiệm này có thể được tự động hóa trong nhiều kiểu thời trang thông qua nhiều công cụ cmd, UI, v.v ...
Aaron McIver

6
@AaronMcIver: Các tập lệnh Shell khá tốt trong việc chạy thử nghiệm trên (ngôn ngữ không phải là Java). Làm thế nào bạn sẽ sử dụng JUnit cho điều đó?
Ben Voigt

1
@BenVoigt Ban đầu tôi cho rằng OP có Java tham gia và đang tìm cách bỏ qua JUnit làm khai thác thử nghiệm. Điều này rất có thể không phải là trường hợp sau khi xem xét câu hỏi. Dường như code.google.com/p/shell2junit có thể cung cấp một số sử dụng cho OP sau lần xem thứ hai.
Aaron McIver

1
Dọc theo dòng shell2unit ở đây là một lớp JAXB mà tôi đã tạo có thể phân tích / xuất ra JUnit XML: gist.github.com/agentgt/8583649
Adam Gent

Câu trả lời:


127

Tôi đã làm một điều tương tự vài tháng trước, và hóa ra định dạng đơn giản này là đủ để Hudson chấp nhận nó như một giao thức thử nghiệm:

<testsuite tests="3">
    <testcase classname="foo1" name="ASuccessfulTest"/>
    <testcase classname="foo2" name="AnotherSuccessfulTest"/>
    <testcase classname="foo3" name="AFailingTest">
        <failure type="NotEnoughFoo"> details about failure </failure>
    </testcase>
</testsuite>

Câu hỏi này có câu trả lời với nhiều chi tiết hơn: Spec. cho đầu ra XML của JUnit


Vui lòng chỉnh sửa câu trả lời này, vì plugin xunit từ chối thuộc tính 'classname' và chỉ chấp nhận 'class'
andho

10
tôi đã có vấn đề ngược lại. classđã bị từ chối và chỉ classnamelàm việc.
ryanbrainard

1
Điều này bắt đầu thất bại đối với tôi khi tôi nâng cấp plugin xUnit lên 1.60. Tôi thấy rằng trình xác nhận trở nên chặt chẽ hơn và tôi phải thêm <testsuite tests="(number of tests)">ex. <testsuite tests="10">.
Kevin Brotcke

2
Cảm ơn @KevinBrotcke, tôi sẽ cập nhật câu trả lời để bao gồm thuộc tính đó.
Anders Lindahl

2
Cũng lưu ý rằng để Hudson tổ chức các bài kiểm tra của bạn theo gói / bộ, bạn phải chỉ định một gói trong thuộc tính tên lớp. ví dụ: <testcase classname="foo.bar" name="ATest" /> Điều này sẽ đặt lớp thanh trong gói foo trên Jenkins làm cho bộ sưu tập thử nghiệm của bạn có tổ chức hơn.
jluzwick

90

Tôi vừa lấy được Junit-4.xsd mà những người khác đã liên kết và sử dụng một công cụ có tên XMLSpear để chuyển đổi lược đồ thành tệp XML trống với các tùy chọn được hiển thị bên dưới. Đây là kết quả (hơi sạch lên):

<?xml version="1.0" encoding="UTF-8"?>
<testsuites disabled="" errors="" failures="" name="" tests="" time="">
    <testsuite disabled="" errors="" failures="" hostname="" id=""
               name="" package="" skipped="" tests="" time="" timestamp="">
        <properties>
            <property name="" value=""/>
        </properties>
        <testcase assertions="" classname="" name="" status="" time="">
            <skipped/>
            <error message="" type=""/>
            <failure message="" type=""/>
            <system-out/>
            <system-err/>
        </testcase>
        <system-out/>
        <system-err/>
    </testsuite>
</testsuites>

Một số mặt hàng này có thể xảy ra nhiều lần:

  • Chỉ có thể có một testsuitesphần tử, vì đó là cách XML hoạt động, nhưng có thể có nhiều testsuitephần tử trong testsuitesphần tử.
  • Mỗi propertiesyếu tố có thể có nhiều propertycon.
  • Mỗi testsuiteyếu tố có thể có nhiều testcasecon.
  • Mỗi testcasephần tử có thể có nhiều error, failure, system-out, hoặc system-errtrẻ em.

Tùy chọn XMLSpear


1
Có tài liệu nào mô tả các giá trị hợp lệ của các thuộc tính nhất định, như trạng thái của testcase hoặc loại lỗi không?
Eric đối phó

1
@EricCope Tôi có thể khuyên bạn nên xem mã nguồn svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ . Về cơ bản nó chỉ là một chuỗi.
Sulthan

4
Tại sao các thẻ được nhân đôi?
Nakilon

thiết lập phản ánh: imgur.com/quneFJf alt: Rootelement: testsuites, Max recursive de...: 2, Max Repeat factor: 2, include optional elements: (yes = đánh dấu), include optional attributes: (yes = đánh dấu)
n611x007

1
@Nakilon Đã trễ 2,5 năm, nhưng tôi đã sửa nó
bdesham

45

Các câu trả lời hàng đầu của câu hỏi Anders Lindahl đề cập đến một tập tin XSD .

Cá nhân tôi thấy tệp xsd này cũng rất hữu ích (tôi không nhớ làm thế nào tôi tìm thấy tệp đó). Nó trông có vẻ ít đáng sợ hơn, và theo như tôi đã sử dụng, tất cả các yếu tố và thuộc tính dường như được Jenkins (v1.451) nhận ra

Một điều mặc dù: khi thêm nhiều <failure ...yếu tố, chỉ có một yếu tố được giữ lại trong Jenkins. Khi tạo tệp xml, bây giờ tôi ghép tất cả các lỗi trong một.


Cập nhật 2016-11 Liên kết bị hỏng ngay bây giờ. Một thay thế tốt hơn là trang này từ cub.org: Định dạng tệp báo cáo XML JUnit , trong đó một nỗ lực tốt đẹp đã được thực hiện để cung cấp một ví dụ tài liệu hợp lý . Ví dụ và xsd được sao chép bên dưới, nhưng trang của chúng trông đẹp hơn.


tệp XML JUnit mẫu

<?xml version="1.0" encoding="UTF-8"?>
<!-- a description of the JUnit XML format and how Jenkins parses it. See also junit.xsd -->

<!-- if only a single testsuite element is present, the testsuites
     element can be omitted. All attributes are optional. -->
<testsuites disabled="" <!-- total number of disabled tests from all testsuites. -->
            errors=""   <!-- total number of tests with error result from all testsuites. -->
            failures="" <!-- total number of failed tests from all testsuites. -->
            name=""
            tests=""    <!-- total number of successful tests from all testsuites. -->
            time=""     <!-- time in seconds to execute all test suites. -->
        >

  <!-- testsuite can appear multiple times, if contained in a testsuites element.
       It can also be the root element. -->
  <testsuite name=""      <!-- Full (class) name of the test for non-aggregated testsuite documents.
                               Class name without the package for aggregated testsuites documents. Required -->
         tests=""     <!-- The total number of tests in the suite, required. -->
         disabled=""  <!-- the total number of disabled tests in the suite. optional -->
             errors=""    <!-- The total number of tests in the suite that errored. An errored test is one that had an unanticipated problem,
                               for example an unchecked throwable; or a problem with the implementation of the test. optional -->
             failures=""  <!-- 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. optional -->
             hostname=""  <!-- Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined. optional -->
         id=""        <!-- Starts at 0 for the first testsuite and is incremented by 1 for each following testsuite -->
         package=""   <!-- Derived from testsuite/@name in the non-aggregated documents. optional -->
         skipped=""   <!-- The total number of skipped tests. optional -->
         time=""      <!-- Time taken (in seconds) to execute the tests in the suite. optional -->
         timestamp="" <!-- when the test was executed in ISO 8601 format (2014-01-21T16:17:18). Timezone may not be specified. optional -->
         >

    <!-- Properties (e.g., environment settings) set during test
     execution. The properties element can appear 0 or once. -->
    <properties>
      <!-- property can appear multiple times. The name and value attributres are required. -->
      <property name="" value=""/>
    </properties>

    <!-- testcase can appear multiple times, see /testsuites/testsuite@tests -->
    <testcase name=""       <!-- Name of the test method, required. -->
          assertions="" <!-- number of assertions in the test case. optional -->
          classname=""  <!-- Full class name for the class the test method is in. required -->
          status=""
          time=""       <!-- Time taken (in seconds) to execute the test. optional -->
          >

      <!-- If the test was not executed or failed, you can specify one
           the skipped, error or failure elements. -->

      <!-- skipped can appear 0 or once. optional -->
      <skipped/>

      <!-- Indicates that the test errored. An errored test is one
           that had an unanticipated problem. For example an unchecked
           throwable or a problem with the implementation of the
           test. Contains as a text node relevant data for the error,
           for example a stack trace. optional -->
      <error message="" <!-- The error message. e.g., if a java exception is thrown, the return value of getMessage() -->
         type=""    <!-- The type of error that occured. e.g., if a java execption is thrown the full class name of the exception. -->
         ></error>

      <!-- Indicates that the test failed. A failure is a test which
       the code has explicitly failed by using the mechanisms for
       that purpose. For example via an assertEquals. Contains as
       a text node relevant data for the failure, e.g., a stack
       trace. optional -->
      <failure message="" <!-- The message specified in the assert. -->
           type=""    <!-- The type of the assert. -->
           ></failure>

      <!-- Data that was written to standard out while the test was executed. optional -->
      <system-out></system-out>

      <!-- Data that was written to standard error while the test was executed. optional -->
      <system-err></system-err>
    </testcase>

    <!-- Data that was written to standard out while the test suite was executed. optional -->
    <system-out></system-out>
    <!-- Data that was written to standard error while the test suite was executed. optional -->
    <system-err></system-err>
  </testsuite>
</testsuites>

Tệp JSDit XSD

<?xml version="1.0" encoding="UTF-8" ?>
<!-- from https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="failure">
        <xs:complexType mixed="true">
            <xs:attribute name="type" type="xs:string" use="optional"/>
            <xs:attribute name="message" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="error">
        <xs:complexType mixed="true">
            <xs:attribute name="type" type="xs:string" use="optional"/>
            <xs:attribute name="message" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="properties">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="property" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="property">
        <xs:complexType>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="value" type="xs:string" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="skipped" type="xs:string"/>
    <xs:element name="system-err" type="xs:string"/>
    <xs:element name="system-out" type="xs:string"/>

    <xs:element name="testcase">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
                <xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="assertions" type="xs:string" use="optional"/>
            <xs:attribute name="time" type="xs:string" use="optional"/>
            <xs:attribute name="classname" type="xs:string" use="optional"/>
            <xs:attribute name="status" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="testsuite">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
                <xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
                <xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="tests" type="xs:string" use="required"/>
            <xs:attribute name="failures" type="xs:string" use="optional"/>
            <xs:attribute name="errors" type="xs:string" use="optional"/>
            <xs:attribute name="time" type="xs:string" use="optional"/>
            <xs:attribute name="disabled" type="xs:string" use="optional"/>
            <xs:attribute name="skipped" type="xs:string" use="optional"/>
            <xs:attribute name="timestamp" type="xs:string" use="optional"/>
            <xs:attribute name="hostname" type="xs:string" use="optional"/>
            <xs:attribute name="id" type="xs:string" use="optional"/>
            <xs:attribute name="package" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="testsuites">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="optional"/>
            <xs:attribute name="time" type="xs:string" use="optional"/>
            <xs:attribute name="tests" type="xs:string" use="optional"/>
            <xs:attribute name="failures" type="xs:string" use="optional"/>
            <xs:attribute name="disabled" type="xs:string" use="optional"/>
            <xs:attribute name="errors" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>

</xs:schema>

Làm thế nào để bạn có được những thất bại để trông đẹp sau đó? Tôi muốn thêm thủ công các ký tự dòng mới nhưng chúng không hiển thị trong Jenkins.
hợp lý hóa

Đó là một bất lợi với cách tiếp cận của tôi. Tôi nhớ vật lộn với cái giếng đó. Cố gắng thêm một cái gì đó như & lt; br / & gt; - Tôi quên cách giải quyết vấn đề này (và chúng tôi không sử dụng điều này nữa), nhưng điều này có vẻ đáng để thử.
parvus

1
Tôi tìm thấy một cách xung quanh nó. Vì chúng tôi đang sử dụng c ++, tôi chỉ báo cáo số lượng lỗi trong thông báo lỗi và sử dụng "Stack Trace" để báo cáo các lỗi thực tế. Vì theo dõi ngăn xếp được báo cáo từ văn bản với phần thân của phần tử lỗi, các dòng mới được hỗ trợ chính xác.
hợp lý

25

Tôi không thể tìm thấy bất kỳ thông tin tốt về điều này, vì vậy tôi đã thực hiện một số thử nghiệm và lỗi. Các thuộc tính và trường sau (và chỉ những trường này) được Jenkins (v1.585) nhận ra.

<?xml version="1.0" encoding="UTF-8"?>
<testsuite>

  <!-- if your classname does not include a dot, the package defaults to "(root)" -->
  <testcase name="my testcase" classname="my package.my classname" time="29">

    <!-- If the test didn't pass, specify ONE of the following 3 cases -->

    <!-- option 1 --> <skipped />
    <!-- option 2 --> <failure message="my failure message">my stack trace</failure>
    <!-- option 3 --> <error message="my error message">my crash report</error>

    <system-out>my STDOUT dump</system-out>

    <system-err>my STDERR dump</system-err>

  </testcase>

</testsuite>

(Tôi đã bắt đầu với tài liệu XML mẫu này và làm việc ngược từ đó.)


6

Cấu trúc cơ bản Dưới đây là một ví dụ về tệp đầu ra JUnit, hiển thị kết quả bỏ qua và không thành công, cũng như một kết quả được thông qua.

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
   <testsuite name="JUnitXmlReporter" errors="0" tests="0" failures="0" time="0" timestamp="2013-05-24T10:23:58" />
   <testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58">
      <properties>
         <property name="java.vendor" value="Sun Microsystems Inc." />
         <property name="compiler.debug" value="on" />
         <property name="project.jdk.classpath" value="jdk.classpath.1.6" />
      </properties>
      <testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006">
         <failure message="test failure">Assertion failed</failure>
      </testcase>
      <testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0">
         <skipped />
      </testcase>
      <testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" />
   </testsuite>
</testsuites>

Dưới đây là cấu trúc tài liệu của một báo cáo XML JUnit điển hình. Lưu ý rằng một báo cáo có thể chứa 1 hoặc nhiều bộ kiểm tra. Mỗi bộ kiểm tra có một tập các thuộc tính (ghi thông tin môi trường). Mỗi bộ kiểm tra cũng chứa 1 hoặc nhiều trường hợp kiểm tra và mỗi trường hợp kiểm thử sẽ chứa một nút bị bỏ qua, lỗi hoặc lỗi nếu kiểm tra không vượt qua. Nếu trường hợp kiểm tra đã qua, thì nó sẽ không chứa bất kỳ nút nào. Để biết thêm chi tiết về các thuộc tính nào là hợp lệ cho mỗi nút, vui lòng tham khảo phần "Lược đồ" sau đây.

<testsuites>        => the aggregated result of all junit testfiles
  <testsuite>       => the output from a single TestSuite
    <properties>    => the defined properties at test execution
      <property>    => name/value pair for a single property
      ...
    </properties>
    <error></error> => optional information, in place of a test case - normally if the tests in the suite could not be found etc.
    <testcase>      => the results from executing a test method
      <system-out>  => data written to System.out during the test run
      <system-err>  => data written to System.err during the test run
      <skipped/>    => test was skipped
      <failure>     => test failed
      <error>       => test encountered an error
    </testcase>
    ...
  </testsuite>
  ...
</testsuites>

4

Có nhiều lược đồ cho kết quả "JUnit" và "xUnit".

Xin lưu ý rằng có một số phiên bản của lược đồ được sử dụng bởi plugin xunit của Jenkins (phiên bản mới nhất hiện tại junit-10.xsdcó thêm hỗ trợ cho định dạng Erlang / OTP Junit).

Một số khung kiểm tra cũng như các plugin báo cáo kiểu "xUnit" cũng sử dụng nước sốt bí mật của riêng họ để tạo báo cáo kiểu "xUnit", chúng không thể sử dụng một lược đồ cụ thể (vui lòng đọc: chúng cố gắng nhưng các công cụ có thể không xác thực với bất kỳ một lược đồ). Con trăn không đáng tin ở Jenkins? đưa ra so sánh nhanh về một vài trong số các thư viện này và sự khác biệt nhỏ giữa các báo cáo xml được tạo.


2

Câu trả lời hay ở đây về việc sử dụng python: (có nhiều cách để làm điều đó) Python unittests in Jenkins?

IMHO cách tốt nhất là viết các bài kiểm tra không đáng tin cậy của pythoncài đặt pytest (một cái gì đó như 'yum install pytest') để cài đặt py.test. Sau đó chạy các bài kiểm tra như thế này: 'py.test --junitxml results.xml test.py' . Bạn có thể chạy bất kỳ tập lệnh python nào nhất và nhận kết quả jUnit xml.

https://docs.python.org/2.7/l Library / unittest.html

Trong cấu hình bản dựng của jenkins Các hành động xây dựng sau Thêm một hành động "Xuất bản báo cáo kết quả kiểm tra JUnit" với tệp kết quả và bất kỳ tệp kết quả kiểm tra nào khác mà bạn tạo ra.


2

Tôi đã quyết định đăng một câu trả lời mới, bởi vì một số câu trả lời hiện có đã lỗi thời hoặc không đầy đủ.

Trước hết: không có gì giống như vậy JUnit XML Format Specification, đơn giản là vì JUnit không tạo ra bất kỳ loại báo cáo XML hoặc HTML nào.

Bản thân việc tạo báo cáo XML xuất phát từ tác vụ Ant JUnit / Maven Surefire Plugin / Gradle (bất cứ khi nào bạn sử dụng để chạy thử nghiệm). Định dạng báo cáo XML được Ant giới thiệu lần đầu tiên và sau đó được điều chỉnh bởi Maven (và Gradle).

Nếu ai đó chỉ cần một định dạng XML chính thức thì:

  1. Tồn tại một lược đồ cho một báo cáo XML do mfire Surefire tạo và nó có thể được tìm thấy ở đây: Surefire-test-report.xsd .
  2. Đối với một XML được tạo ra có một lược đồ bên thứ 3 có sẵn ở đây (nhưng nó có thể hơi lỗi thời).

Hy vọng nó sẽ giúp được ai đó.


Cảm ơn sự trình bày rõ ràng của bạn. Tôi đang cố gắng gửi bản tóm tắt kiểm tra JUnit từ một phiên bản cũ của Jenkins 1.6 đến Slack - bạn có thể giúp gì không? Tôi sẽ đặt một tệp XML như vậy ở đâu?
JJD

@JJD Xin lỗi, tôi không hiểu bạn. Ý nghĩa chính xác của tệp XML đó là gì? Nhưng tôi giả sử bạn đã chạy các bài kiểm tra JUnit của mình với ant / maven / gradle, đúng không? Nếu có, các công cụ này, sau khi thực hiện kiểm tra, tạo báo cáo tóm tắt tốt đẹp. Phiên bản của Jenkins không quan trọng ở đây.
G. Demecki

Vâng, bản dựng của tôi chạy qua Gradle. Tôi muốn gửi bản tóm tắt kiểm tra JUnit tới kênh Slack trong khi sử dụng Jenkins 1.6. Đọc thảo luận về GitHub tôi nghĩ rằng tôi phải đặt một tệp XML cấu hình ở đâu đó để cho plugin Slack chọn bản tóm tắt thử nghiệm. Có lẽ tôi hiểu lầm.
JJD

1
Vui lòng kiểm tra xem các báo cáo kiểm tra được tạo chính xác có tồn tại sau khi Gradle hoàn thành việc khởi chạy các bài kiểm tra JUnit của bạn. Sau đó, plugin Slack sẽ có thể sử dụng các báo cáo này.
G. Demecki

1
Cuối cùng, lời khuyên của bạn đã đẩy tôi đi đúng hướng: Tôi phải cấu hình đúng đường dẫn để tìm các tệp XML . Đối với dự án Android của tôi có nhiều hương vị sản phẩm Gradle , các công việc sau : **/build/test-results/**/TEST-*.xml. Cảm ơn rât nhiều!!!
JJD
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.