Apa spesifikasi format XML JUnit yang didukung Hudson?

183

Saya menggunakan Hudson sebagai server integrasi berkelanjutan dan saya ingin menggunakan opsi 'Publikasikan laporan hasil pengujian JUnit'. Tapi saya tidak menggunakan alat xUnit untuk pengujian, alih-alih saya punya skrip shell yang menjalankan tes dan mengembalikan hasil dalam format sederhana. Saya berpikir untuk membuat skrip yang mengubah hasil ini ke format JUnit. Jadi saya menarik bagaimana file JUnit harus terlihat?

krvladislav
sumber
Ada alasan untuk tidak menggunakan JUnit? Tes-tes ini dapat diotomatisasi dalam berbagai mode melalui berbagai alat cmd, UI, dll ...
Aaron McIver
6
@AaronMcIver: Skrip shell cukup bagus dalam menjalankan tes (bahasa yang bukan Java). Bagaimana Anda menggunakan JUnit untuk itu?
Ben Voigt
1
@ BenVoigt Saya awalnya berasumsi OP telah melibatkan Java dan ingin memotong JUnit sebagai harness pengujian. Ini kemungkinan besar tidak terjadi setelah meninjau pertanyaan. Tampaknya code.google.com/p/shell2junit dapat menyediakan beberapa kegunaan untuk OP setelah pandangan kedua.
Aaron McIver
1
Di sepanjang baris shell2unit di sini adalah kelas JAXB yang saya buat yang dapat menguraikan / output JUnit XML: gist.github.com/agentgt/8583649
Adam Gent

Jawaban:

127

Saya melakukan hal serupa beberapa bulan yang lalu, dan ternyata format sederhana ini sudah cukup bagi Hudson untuk menerimanya sebagai protokol uji:

<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>

Pertanyaan ini memiliki jawaban dengan rincian lebih lanjut: Spec. untuk JUnit XML Output

Anders Lindahl
sumber
Harap perbaiki jawaban ini, karena plugin xunit menolak atribut 'classname' dan menerima 'class' saja
danho
10
Saya punya masalah sebaliknya. classditolak dan hanya classnameberfungsi.
ryanbrainard
1
Ini mulai gagal bagi saya ketika saya memutakhirkan plugin xUnit menjadi 1,60. Saya menemukan bahwa validator menjadi lebih ketat dan saya harus menambahkan <testsuite tests="(number of tests)">mantan. <testsuite tests="10">.
Kevin Brotcke
2
Terima kasih @KevinBrotcke, saya akan memperbarui jawaban untuk menyertakan atribut itu.
Anders Lindahl
2
Perhatikan juga bahwa agar Hudson mengatur pengujian Anda dengan paket / paket, Anda harus menentukan paket dalam atribut classname. mis: <testcase classname="foo.bar" name="ATest" /> Ini akan menempatkan kelas bar dalam paket foo di Jenkins membuat koleksi tes Anda lebih terorganisir.
jluzwick
90

Saya baru saja meraih junit-4.xsd yang telah ditautkan oleh orang lain dan menggunakan alat bernama XMLSpear untuk mengubah skema menjadi file XML kosong dengan opsi yang ditunjukkan di bawah ini. Ini adalah hasil (sedikit dibersihkan):

<?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>

Beberapa item ini dapat terjadi beberapa kali:

  • Hanya ada satu testsuiteselemen, karena itulah cara kerja XML, tetapi bisa ada banyak testsuiteelemen di dalam testsuiteselemen.
  • Setiap propertieselemen dapat memiliki beberapapropertyanak.
  • Setiap testsuiteelemen dapat memiliki beberapa testcaseanak.
  • Setiap testcaseelemen dapat memiliki beberapa error, failure, system-out, atau system-erranak-anak.

Opsi XMLSpear

Todd Mazierski
sumber
1
Apakah ada dokumen yang menjelaskan nilai valid atribut tertentu, seperti status testcase atau tipe kesalahan?
Eric Cope
1
@EricCope Saya dapat merekomendasikan melihat kode sumber svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/… . Pada dasarnya itu hanya sebuah string.
Sulthan
4
Mengapa tag digandakan?
Nakilon
pengaturan cermin: imgur.com/quneFJf alt: Rootelement: testsuites, Max recursive de...: 2, Max Repeat factor: 2, include optional elements: (ya = dicentang), include optional attributes: (ya = dicentang)
n611x007
1
@Nakilon Sudah terlambat 2,5 tahun, tapi saya memperbaikinya
bdesham
45

The jawaban atas pertanyaan Anders Lindahl mengacu pada berkas xsd .

Secara pribadi saya menemukan file xsd ini juga sangat berguna (saya tidak ingat bagaimana saya menemukan itu). Itu terlihat agak kurang menakutkan, dan sejauh yang saya gunakan, semua elemen dan atribut tampaknya dikenali oleh Jenkins (v1.451)

Namun satu hal: ketika menambahkan beberapa <failure ...elemen, hanya satu yang dipertahankan di Jenkins. Saat membuat file xml, saya sekarang menggabungkan semua kegagalan dalam satu.


Pembaruan 2016-11 Tautan rusak sekarang. Alternatif yang lebih baik adalah halaman ini dari cubic.org: JUnit XML format file pelaporan , di mana upaya yang baik telah diambil untuk memberikan contoh yang didokumentasikan masuk akal . Contoh dan xsd disalin di bawah, tetapi halaman mereka terlihat lebih bagus.


contoh file XML JUnit

<?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>

JUnit file 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>
parvus
sumber
Bagaimana Anda mendapatkan kegagalan untuk terlihat bagus? Saya ingin menambahkan karakter garis baru secara manual tetapi tidak muncul di Jenkins.
rationalcoder
Itu kerugian dengan pendekatan saya. Saya ingat berjuang dengan sumur itu. Coba tambahkan sesuatu seperti & lt; br / & gt; - Saya lupa bagaimana ini diselesaikan (dan kami tidak menggunakan ini lagi), tapi ini sepertinya sesuatu yang patut dicoba.
parvus
1
Saya menemukan jalan keluar. Karena kita menggunakan c ++ saya hanya melaporkan jumlah kegagalan dalam pesan kegagalan dan menggunakan "Stack Trace" untuk melaporkan kegagalan yang sebenarnya. Karena jejak tumpukan dilaporkan dari teks dengan isi elemen kegagalan, baris baru didukung dengan benar.
rationalcoder
25

Saya tidak dapat menemukan informasi yang bagus tentang ini, jadi saya melakukan beberapa percobaan. Atribut dan bidang berikut (dan hanya ini) dikenali oleh Jenkins (v1.585).

<?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>

(Saya mulai dengan dokumen XML sampel ini dan bekerja mundur dari sana.)

Ian
sumber
6

Struktur Dasar Berikut adalah contoh file output JUnit, menampilkan hasil lewati dan gagal, serta hasil tunggal yang dilewati.

<?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>

Di bawah ini adalah struktur terdokumentasi dari laporan XML JUnit yang khas. Perhatikan bahwa laporan dapat berisi 1 atau lebih paket uji. Setiap rangkaian uji memiliki serangkaian properti (merekam informasi lingkungan). Setiap test suite juga mengandung 1 atau lebih test case dan masing-masing test case akan berisi simpul yang dilewati, gagal atau kesalahan jika tes tidak lulus. Jika test case telah lulus, maka tidak akan berisi node. Untuk detail lebih lanjut tentang atribut mana yang valid untuk setiap node, bacalah bagian "Skema" berikut.

<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>
Nayana Adassuriya
sumber
4

Ada beberapa skema untuk hasil "JUnit" dan "xUnit".

Harap dicatat bahwa ada beberapa versi skema yang digunakan oleh Jenkins xunit-plugin (versi terbaru saat ini adalah junit-10.xsdyang menambahkan dukungan untuk format Erlang / OTP Junit).

Beberapa kerangka kerja pengujian serta plugin pelaporan gaya "xUnit" juga menggunakan saus rahasia mereka sendiri untuk menghasilkan laporan gaya "xUnit", yang mungkin tidak menggunakan skema tertentu (baca: mereka mencoba tetapi alat mungkin tidak memvalidasi terhadap apa pun satu skema). Python unittests di Jenkins? memberikan perbandingan cepat dari beberapa pustaka ini dan sedikit perbedaan antara laporan xml yang dihasilkan.

tidak tahu
sumber
2

Jawaban yang bagus di sini tentang penggunaan python: (ada banyak cara untuk melakukannya) Python unittests di Jenkins?

IMHO cara terbaik adalah menulis tes unittest python dan menginstal pytest (sesuatu seperti 'yum install pytest') untuk menginstal py.test. Kemudian jalankan tes seperti ini: 'py.test --junitxml results.xml test.py' . Anda dapat menjalankan skrip python unittest dan mendapatkan hasil xml jUnit.

https://docs.python.org/2.7/library/unittest.html

Dalam konfigurasi jenkins build Post-build tindakan Tambahkan tindakan "Publikasikan laporan hasil tes JUnit" dengan result.xml dan file hasil tes lagi yang Anda hasilkan.

gaoithe
sumber
2

Saya telah memutuskan untuk mengirim jawaban baru, karena beberapa jawaban yang ada sudah usang atau tidak lengkap.

Pertama-tama: tidak ada yang seperti itu JUnit XML Format Specification, hanya karena JUnit tidak menghasilkan laporan XML atau HTML apa pun.

Pembuatan laporan XML itu sendiri berasal dari tugas Ant JUnit / Maven Surefire Plugin / Gradle (mana yang Anda gunakan untuk menjalankan tes Anda). Format laporan XML pertama kali diperkenalkan oleh Ant dan kemudian diadaptasi oleh Maven (dan Gradle).

Jika seseorang hanya membutuhkan format XML resmi maka:

  1. Ada skema untuk laporan XML yang dihasilkan oleh maven surefire dan dapat ditemukan di sini: surefire-test-report.xsd .
  2. Untuk XML semut yang dihasilkan, ada skema pihak ke-3 yang tersedia di sini (tetapi mungkin sedikit usang).

Semoga ini bisa membantu seseorang.

G. Demecki
sumber
Terimakasih atas klarifikasi Anda. Saya mencoba mengirim ringkasan uji JUnit dari contoh Jenkins 1.6 ke Slack - mungkin Anda bisa membantu? Di mana saya akan meletakkan file XML seperti itu?
JJD
@JJD Maaf, saya tidak mengerti. Apa yang Anda maksud dengan file XML tersebut ? Tapi saya menganggap Anda sudah menjalankan tes JUnit Anda dengan semut / maven / gradle, ya? Jika ya, alat-alat ini, setelah pengujian dijalankan, menghasilkan laporan ringkasan yang bagus. Versi Jenkins tidak masalah di sini.
G. Demecki
Ya, build saya berjalan melalui Gradle. Saya ingin mengirim ringkasan uji JUnit ke saluran Slack saat menggunakan Jenkins 1.6. Membaca diskusi GitHub, saya pikir saya harus meletakkan file konfigurasi XML di suatu tempat untuk membiarkan plugin Slack mengambil ringkasan tes. Mungkin saya salah paham.
JJD
1
Periksa apakah ada laporan pengujian yang dibuat dengan benar setelah Gradle meluncurkan tes JUnit Anda. Maka plugin Slack harus dapat menggunakan laporan ini.
G. Demecki
1
Akhirnya, saran Anda mendorong saya ke arah yang benar: Saya harus mengkonfigurasi jalur yang benar untuk mencari file XML . Untuk saya Android proyek dengan beberapa rasa produk Gradle , berikut karya: **/build/test-results/**/TEST-*.xml. Terima kasih banyak!!!
JJD