zoukankan      html  css  js  c++  java
  • Using Hudson for C++/CMake/CppUnit

    As a follow-up to Using grails projects in Hudson, here is another not-so-standard usage of Hudson: C++ projects with CMake and CppUnit. Let’s see how that works out.

    As long as you have Java/Ant/JUnit based projects, a fine tool that it is, configuration of Hudson is pretty straight forward. But if you have a C++ project with CMake as build system and CppUnit for your unit testing, you have to dig a little deeper. Fortunately, Hudson provides the possibility to execute arbitrary shell commands. So in order to build the project and execute the tests, we can simply put a shell script to work:

       # define build and installation directories
       BUILD_DIR=$WORKSPACE/build_dir
       INSTALL_DIR=$WORKSPACE/install_dir
    
       # we want to have a clean build
       rm -Rf $BUILD_DIR
       mkdir $BUILD_DIR
       cd $BUILD_DIR
    
       # initializing the build system
       cmake  ..  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR
    
       # fire-up the compiler
       make install

    Environment variable WORKSPACE is defined by Hudson. Other useful variables are e.g. BUILD_NUMBER, BUILD_TAG and CVS_BRANCH.

    But what about those unit tests? Hudson understands JUnit test result files out-of-the-box. So all we have to do is make CppUnit spit out an xml report and then translate it to JUnit form. To help us with that, we need a little xslt transformation. But first, let’s see how we can make CppUnit generate xml results (a little simplified):

    #include <cppunit/necessary/CppUnitIncludes/>
    ...
    
    using namespace std;
    using namespace CppUnit;
    
    int main(int argc, char** argv)
    {
       TestResult    controller;
       TestResultCollector result;
       controller.addListener(&result);
    
       CppUnit::TextUi::TestRunner runner;
       runner.addTest( TestFactoryRegistry::getRegistry().makeTest() );
       runner.run(controller);
    
       // important stuff happens next
       ofstream xmlFileOut("cpptestresults.xml");
       XmlOutputter xmlOut(&result, xmlFileOut);
       xmlOut.write();
    }

    The assumption here is that your unit tests are built into libraries that are linked with the main function above. To execute the unit tests we add the following to out shell script:

       export PATH=$INSTALL_DIR/bin:$PATH
       export LD_LIBRARY_PATH=$INSTALL_DIR/lib:$LD_LIBRARY_PATH
    
       # call the cppunit executable
       cd $WORKSPACE
       cppunittests

    This results in CppUnit generating file $WORKSPACE/cpptestresults.xml. Now, with the help of a little program called xsltproc and the following little piece of XSLT code, we can translate cpptestresults.xml to testresults.xml in JUnit format.

     <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
        <xsl:template match="/">
            <testsuite>
                <xsl:attribute name="errors"><xsl:value-of select="TestRun/Statistics/Errors"/></xsl:attribute>
                <xsl:attribute name="failures">
                    <xsl:value-of select="TestRun/Statistics/Failures"/>
                </xsl:attribute>
                <xsl:attribute name="tests">
                    <xsl:value-of select="TestRun/Statistics/Tests"/>
                </xsl:attribute>
                <xsl:attribute name="name">from cppunit</xsl:attribute>
                <xsl:apply-templates/>
            </testsuite>
        </xsl:template>
        <xsl:template match="/TestRun/SuccessfulTests/Test">
            <testcase>
                <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
                <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
            </testcase>
        </xsl:template>
        <xsl:template match="/TestRun/FailedTests/FailedTest">
            <testcase>
                <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
                <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
                <error>
                    <xsl:attribute name="message">
                        <xsl:value-of select=" normalize-space(Message)"/>
                    </xsl:attribute>
                    <xsl:attribute name="type">
                        <xsl:value-of select="FailureType"/>
                    </xsl:attribute>
                    <xsl:value-of select="Message"/>
                    File:<xsl:value-of select="Location/File"/>
                    Line:<xsl:value-of select="Location/Line"/>
                </error>
            </testcase>
        </xsl:template>
        <xsl:template match="text()|@*"/>
    </xsl:stylesheet>

    The following call goes into our shell script:

    xsltproc cppunit2junit.xsl $WORKSPACE/cpptestresults.xml > $WORKSPACE/testresults.xml

    In the configuration page we can now check “Display JUnit test results” and give testresults.xml as result file. As a last step, we can package everything in $WORKSPACE/install_dir into a .tgz file and have Hudson to store it as build artifact. That’s it!

    As always, there is room for improvements. One would be to wrap the shell script code above in a separate bash script and have Hudson simply call that script. The only advantage of the approach above is that you can see what’s going on directly on the configuration page. If your project is bigger, you might have more than one CppUnit executable. In this case, you can for example generate all testresult.xml files into a separate directory and tell Hudson to take into account all .xml files there.

    Update: For the CMake related part of the above shell script I recently published the first version of a cmakebuilder plugin for Hudson. Check out my corresponding blog post.

  • 相关阅读:
    转:SVN常见问题与解决方法
    Mac OS 下的解压缩软件——The Unarchiver
    Django报错 The serializer field might be named incorrectly and not match any Got AttributeError when attempting to get a value for field `author_for` on serializer `KnownledgeBaseListSerializer`
    Django 生成数据库表时的报错TypeError: __init__() missing 1 required positional argument: 'on_delete'
    webstorm不能中文输入问题
    npm报错This is probably not a problem with npm. There is likely additional logging
    Django 报错no sucn column: OpretionalError
    Python 报错 AttributeError: module 'django.db.models' has no attribute 'SubfieldBase'
    详解Django中Request对象的相关用法
    Python中import, from...import,import...as的区别
  • 原文地址:https://www.cnblogs.com/kevinzhwl/p/1847838.html
Copyright © 2011-2022 走看看