Home > Mobile >  How to get Boost Unit Test to show filename on JUnit testcase attribute?
How to get Boost Unit Test to show filename on JUnit testcase attribute?

Time:01-12

I know Boost can see the filename as when you set the reporter level to detailed and the logger level to all, the filename (even the line number) are shown.

For example, if I call the test executable like

$ ./test --log_level=all --report_level=detailed

I get

Running 1 test case...
Entering test module "simple_class"
/path/to/test_constructor.cpp(28): Entering test suite "simple_class_constructor"
/path/to/test_constructor.cpp(29): Entering test case "default"
/path/to/test_constructor.cpp(30): info: check 'no exceptions thrown by simple_class()' has passed
/path/to/test_constructor.cpp(29): Leaving test case "default"; testing time: 2909us
Leaving test module "simple_class"; testing time: 2955us

Test module "simple_class" has passed with:
  1 test case out of 1 passed
  1 assertion out of 1 passed

  Test suite "simple_class_constructor" has passed with:
    1 test case out of 1 passed
    1 assertion out of 1 passed

    Test case "bool_card_constructor/default" has passed with:
      1 assertion out of 1 passed

But if I call the executable like

$ ./test --log_level=all --log_format=JUNIT --report_level=no

I get

<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="1" skipped="0" errors="0" failures="0" id="0" name="simple_class" time="0.002691">
<testcase assertions="1" classname="simple_class_constructor" name="default" time="0.002217">
<system-out><![CDATA[INFO:
- file   : test_constructor.cpp
- line   : 30
- message: check 'no exceptions thrown by simple_class()' has passed

]]></system-out>
</testcase>
</testsuite>

In this last format, you can see that the information is inside the system-out tag, but I want it to be in the testcase attributes.

Questions

  • Is there a way to get the filename on which the test suite/case is located on the testcase attributes in the JUnit logger on Boost Unit Test?

  • In case is not possible inside Boost Unit Test, is if possible to do the "correction" via shell scripting or similar and how?

CodePudding user response:

You can cross reference with the output of the XML reporter:

build/sotest --log_level=all --log_format=JUNIT --report_level=no
<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="1" skipped="0" errors="0" failures="1" id="0" name="sotest" time="0.000131">
<testcase assertions="1" classname="Demo" name="Foo" time="0.000114">
<failure message="failure" type="assertion error"><![CDATA[
ASSERTION FAILURE:
- file   : test.cpp
- line   : 8
- message: check 1==2 has failed

]]></failure><system-err><![CDATA[Failures detected in:
- test case: Demo/Foo
- file: test.cpp
- line: 7
]]></system-err>
</testcase>
</testsuite>
build/sotest --log_level=all --log_format=XML --report_level=no
<TestLog><TestSuite name="sotest"><TestSuite name="Demo" file="/home/sehe/Projects/stackoverflow/test.cpp" line="5"><TestCase name="Foo" file="/home/sehe/Projects/stackoverflow/test.cpp" line="7"><Error file="/home/sehe/Projects/stackoverflow/test.cpp" line="8"><![CDATA[check 1==2 has failed]]></Error><TestingTime>104</TestingTime></TestCase></TestSuite></TestSuite></TestLog>

In fact, the XML output might be what you need!

Demo

Let's use this trivial test:

#define BOOST_TEST_MODULE sotest
#include <boost/test/unit_test.hpp>
#include <boost/test/included/unit_test_framework.hpp>

BOOST_AUTO_TEST_SUITE(SuiteA)
BOOST_AUTO_TEST_CASE(Foo) { BOOST_CHECK(1==2); }
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(SuiteB)
BOOST_AUTO_TEST_CASE(Foo) { BOOST_CHECK(2==3); }
BOOST_AUTO_TEST_SUITE_END()

To use XSLT to correlate both, write both to separate files, e.g.:

sotest --logger=XML,all,b.xml:JUNIT,all,a.xml

Now using saxon-he:

java -jar /home/sehe/custom/Saxon/saxon-he-11.3.jar -xsl:merge.xslt -s:a.xml

Where merge.xslt is a quick and dirty stylesheet I came up with:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  
  <xsl:output method="xml" indent="yes"/>
  
  <xsl:param name="xmlreport_filename" select="'b.xml'"/>
  <xsl:variable name="xmlreport" select="document($xmlreport_filename)"/>
  
  <!--<xsl:key name="k1" match="TestLog/TestSuite/TestSuite/TestCase" use="@name"/>-->
  <xsl:key name="k1" match="TestCase" use="@name"/>
  
  <xsl:template match="testsuite/testcase">
    <xsl:element name="{local-name()}">
      <xsl:variable name="expectedclass" select="@classname"/>
      <xsl:copy-of select="@*"/>
      <!--extra attributes-->
      <xsl:for-each select="key('k1', @name, $xmlreport)">
        <xsl:if test="..[@name=$expectedclass]">
          <xsl:copy-of select="@file|@line"/>
        </xsl:if>
      </xsl:for-each>
      <!--annotating with elements, demonstration-->
      <xsl:for-each select="key('k1', @name, $xmlreport)">
        <annotation>
          <xsl:choose>
            <xsl:when test="..[@name=$expectedclass]">
              <xsl:copy-of select=".."/>
            </xsl:when>
            <xsl:otherwise>
              <warning reason="mismatched">
                <xsl:attribute name='expectedclass'> <xsl:value-of select='$expectedclass'/> </xsl:attribute>
                <xsl:attribute name='actualclass'> <xsl:value-of select='../@name'/> </xsl:attribute>
                <!--<xsl:copy-of select=".."/>-->
              </warning>
            </xsl:otherwise>
          </xsl:choose>
        </annotation>
      </xsl:for-each>
      <xsl:copy-of select="*"/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="testsuite">
      <xsl:element name="{local-name()}">
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>

</xsl:stylesheet>

This has the output

<?xml version="1.0" encoding="UTF-8"?>
<testsuite>
   <testcase assertions="1"
              classname="SuiteA"
              name="Foo"
              time="0.000107"
              file="/home/sehe/Projects/stackoverflow/test.cpp"
              line="6">
      <annotation>
         <TestSuite name="SuiteA"
                     file="/home/sehe/Projects/stackoverflow/test.cpp"
                     line="5">
            <TestCase name="Foo"
                       file="/home/sehe/Projects/stackoverflow/test.cpp"
                       line="6">
               <Error file="/home/sehe/Projects/stackoverflow/test.cpp" line="6">check 1==2 has failed</Error>
               <TestingTime>107</TestingTime>
            </TestCase>
         </TestSuite>
      </annotation>
      <annotation>
         <warning reason="mismatched" expected actual/>
      </annotation>
      <failure message="failure" type="assertion error">
ASSERTION FAILURE:
- file   : test.cpp
- line   : 6
- message: check 1==2 has failed

</failure>
      <system-err>Failures detected in:
- test case: SuiteA/Foo
- file: test.cpp
- line: 6
</system-err>
   </testcase>
   <testcase assertions="1"
              classname="SuiteB"
              name="Foo"
              time="9.2e-05"
              file="/home/sehe/Projects/stackoverflow/test.cpp"
              line="10">
      <annotation>
         <warning reason="mismatched" expected actual/>
      </annotation>
      <annotation>
         <TestSuite name="SuiteB"
                     file="/home/sehe/Projects/stackoverflow/test.cpp"
                     line="9">
            <TestCase name="Foo"
                       file="/home/sehe/Projects/stackoverflow/test.cpp"
                       line="10">
               <Error file="/home/sehe/Projects/stackoverflow/test.cpp" line="10">check 2==3 has failed</Error>
               <TestingTime>92</TestingTime>
            </TestCase>
         </TestSuite>
      </annotation>
      <failure message="failure" type="assertion error">
ASSERTION FAILURE:
- file   : test.cpp
- line   : 10
- message: check 2==3 has failed

</failure>
      <system-err>Failures detected in:
- test case: SuiteB/Foo
- file: test.cpp
- line: 10
</system-err>
   </testcase>
</testsuite>

CAVEAT

Note this happens to work for the simple example, you will have to test/adapt to your real test output.

  • Related