Java 8,Jenkins,Jacoco和Sonar进行持续集成
技术环境
在以安全与质量为主要驱动力的项目中,CI至关重要。
因此,我从我的团队开始进行“概念验证”,以表明以下技术已准备好协同工作:
- Java 8, NetBeans 8.0 & Ant
 - JUnit 4 & Jacoco 0.7.1
 - Jenkins & Sonar 4.2
 
本文的范围是解释安装和设置必要工具的所有步骤,以使Java 8的CI服务器完全正常运行。请注意,该证明已在Windows 7的开发人员机器上完成,但很容易做到。在Linux服务器中也是如此。
下图高层次显示了将在帖子中描述的体系结构。

Java 8 & NetBeans 8.0 & Ant
我们正在创建模块化应用程序。该应用程序具有多层体系结构,其中每个层都是模块套件,而最终的可执行文件只是一组集成套件。
我们正在使用Ant 来构建我们的项目,但是如果您使用的是Maven,则甚至可以简化该过程,因为Jenkins中的Sonar集成可以通过使用Maven的插件来完成。
JUnit 4 & Jacoco 0.7.1
自然,我们正在进行单元测试,因此,我们使用JUnit4。它在任何地方都可以很好地集成,尤其是在NetBeans中。
Jacoco 是生成代码覆盖率的绝佳工具,并且自0.7.1版起,它完全支持Java 8。
Jenkins & Sonar 4.2
Jenkins是我们CI服务器的引擎,它将与上述所有技术集成在一起,没有任何问题。测试的版本是1.554。
声纳正在对代码进行所有质量分析。4.2版与Java 8完全兼容。
将Sonar与Ant一起使用需要一个小型库,其中包含要集成到Jenkins中的目标。如果您使用的是Maven,则可以只安装Maven插件。
项目配置
1、安装Java 8
2、创建一个包含几个模块,几个类和几个jUnit测试的模块套件
3、将代码提交到您的源代码版本管理服务器中
4、在名为“ jacoco-0.7.1”的线束中创建一个文件夹,其中包含下载的jacoco jars
5、在名为“ sonar-ant-task”的线束中创建一个文件夹,并将其放入下载的sonar文件夹
6、在名为sonar-jacoco-module.xml的工具中创建一个文件,并将以下代码粘贴到其中:
<?xml version="1.0" encoding="UTF-8"?>
<!--
-->
<project name="sonar-jacoco-module" basedir="." xmlns:jacoco="antlib:org.jacoco.ant" xmlns:sonar="antlib:org.sonar.ant">
    <description>Builds the module suite otherSuite.</description>
    <property name="jacoco.dir" location="${nbplatform.default.harness.dir}/jacoco-0.7.1"/>
    <property name="result.exec.file" location="${jacoco.dir}/jacoco.exec"/>
    <property name="build.test.results.dir" location="build/test/unit/results"/>
    <property file="nbproject/project.properties"/>
    <!-- Step 1: Import JaCoCo Ant tasks -->
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="${jacoco.dir}/jacocoant.jar"/>
    </taskdef>
    <!-- Target at the level of modules -->
    <target name="-do-junit" depends="test-init">
        <echo message="Doing testing for jacoco"/>
        <macrodef name="junit-impl">
            <attribute name="test.type"/>
            <attribute name="disable.apple.ui" default="false"/>
            <sequential>
                <jacoco:coverage destfile="${build.test.results.dir}/${code.name.base}_jacoco.exec">
                    <junit showoutput="true" fork="true" failureproperty="tests.failed" errorproperty="tests.failed"
                           filtertrace="${test.filter.trace}" tempdir="${build.test.@{test.type}.results.dir}"
                           timeout="${test.timeout}">
                        <batchtest todir="${build.test.@{test.type}.results.dir}">
                            <fileset dir="${build.test.@{test.type}.classes.dir}" includes="${test.includes}"
                                     excludes="${test.excludes}"/>
                        </batchtest>
                        <classpath refid="test.@{test.type}.run.cp"/>
                        <syspropertyset refid="test.@{test.type}.properties"/>
                        <jvmarg value="${test.bootclasspath.prepend.args}"/>
                        <jvmarg line="${test.run.args}"/>
                        <!--needed to have tests NOT to steal focus when running, works in latest apple jdk update only.-->
                        <sysproperty key="apple.awt.UIElement" value="@{disable.apple.ui}"/>
                        <formatter type="brief" usefile="false"/>
                        <formatter type="xml"/>
                    </junit>
                </jacoco:coverage>
                <copy file="${build.test.results.dir}/${code.name.base}_jacoco.exec"
                      todir="${suite.dir}/build/coverage"/>
                <!--
                Copy the result of all the unit tests of all the modules into one common
                folder at the level of the suite, so that sonar could find those files to
                generate associated reports
                -->
                <copy todir="${suite.dir}/build/test-results">
                    <fileset dir="${build.test.results.dir}">
                        <include name="**/TEST*.xml"/>
                    </fileset>
                </copy>
                <fail if="tests.failed" unless="continue.after.failing.tests">Some tests failed; see details above.
                </fail>
            </sequential>
        </macrodef>
        <junit-impl test.type="${run.test.type}" disable.apple.ui="${disable.apple.ui}"/>
    </target>
</project>
该文件的范围是覆盖添加jacoco覆盖范围的do-junit任务,并复制套件构建中每个模块的单元测试结果,以便声纳将找到所有这些元素一起进行分析。
7、在名为sonar-jacoco-suite.xml的线束中创建一个文件,并将以下代码粘贴到其中
<?xml version="1.0" encoding="UTF-8"?>
<project name="sonar-jacoco-suite" basedir="." xmlns:jacoco="antlib:org.jacoco.ant" xmlns:sonar="antlib:org.sonar.ant">
    <description>Builds the module suite otherSuite.</description>
    <property name="jacoco.dir" location="${nbplatform.default.harness.dir}/jacoco-0.7.1"/>
    <property name="result.exec.file" location="build/coverage"/>
    <!-- Define the SonarQube global properties (the most usual way is to pass these properties via the command line) -->
    <property name="sonar.jdbc.url" value="jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8" />
    <property name="sonar.jdbc.username" value="sonar" />
    <property name="sonar.jdbc.password" value="sonar" />
    <!-- Define the SonarQube project properties -->
    <property name="sonar.projectKey" value="org.codehaus.sonar:example-java-ant" />
    <property name="sonar.projectName" value="Simple Java Project analyzed with the SonarQube Ant Task" />
    <property name="sonar.projectVersion" value="1.0" />
    <property name="sonar.language" value="java" />
    <!-- Load the project properties file for retrieving the modules of the suite -->
    <property file="nbproject/project.properties"/>
    <!-- Using Javascript functions to build the paths of the data source for sonar configuration -->
    <script language="javascript">
        <![CDATA[
// getting the value
modulesName = project.getProperty("modules");
modulesName = modulesName.replace(":",",");
res = modulesName.split(",");
srcModules = "";
binariesModules = "";
testModules = "";
//Build the paths
for (var i=0; i<res.length; i++)
{
srcModules += res[i]+"/src,";
binariesModules += res[i]+"/build/classes,";
testModules += res[i]+"/test,";
}
//Remove the last comma
srcModules = srcModules.substring(0, srcModules.length - 1);
binariesModules = binariesModules.substring(0, binariesModules.length - 1);
testModules = testModules.substring(0, testModules.length - 1);
// store the result in a new properties
project.setProperty("srcModulesPath",srcModules);
project.setProperty("binariesModulesPath",binariesModules);
project.setProperty("testModulesPath",testModules);
]]>
    </script>
    <!-- Display the values -->
    <property name="sonar.sources" value="${srcModulesPath}"/>
    <property name="sonar.binaries" value="${binariesModulesPath}" />
    <property name="sonar.tests" value="${testModulesPath}" />
    <!-- Define where the coverage reports are located -->
    <!-- Tells SonarQube to reuse existing reports for unit tests execution and coverage reports -->
    <property name="sonar.dynamicAnalysis" value="reuseReports" />
    <!-- Tells SonarQube where the unit tests execution reports are -->
    <property name="sonar.junit.reportsPath" value="build/test-results" />
    <!-- Tells SonarQube that the code coverage tool by unit tests is JaCoCo -->
    <property name="sonar.java.coveragePlugin" value="jacoco" />
    <!-- Tells SonarQube where the unit tests code coverage report is -->
    <property name="sonar.jacoco.reportPath" value="${result.exec.file}/merged.exec" />
    <!--  Step 1: Import JaCoCo Ant tasks  -->
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="${jacoco.dir}/jacocoant.jar"/>
    </taskdef>
    <target name="merge-coverage">
        <jacoco:merge destfile="${result.exec.file}/merged.exec">
            <fileset dir="${result.exec.file}" includes="*.exec"/>
        </jacoco:merge>
    </target>
    <target name="sonar">
        <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml">
            <!-- Update the following line, or put the "sonar-ant-task-*.jar" file in your "$HOME/.ant/lib" folder -->
            <classpath path="${harness.dir}/sonar-ant-task-2.1/sonar-ant-task-2.1.jar" />
        </taskdef>
        <!-- Execute the SonarQube analysis -->
        <sonar:sonar />
    </target>
</project>
该文件的范围是在套件级别定义声纳配置和声纳任务。如果您使用声纳,则某些特殊的数据库或特殊的用户必须在此处更改配置。
定义的另一项任务是jacoco合并,该合并实际上将获取每个模块的所有生成的exec,并将它们合并到套件构建中的单个exec中,以允许声纳进行分析。
8、用以下内容替换每个模块的build.xml的内容:
<description>Builds, tests, and runs the project com.infrabel.jacoco.</description>
<property file="nbproject/suite.properties"/>
<property file="${suite.dir}/nbproject/private/platform-private.properties"/>
<property file="${user.properties.file}"/>
<import file="${nbplatform.default.harness.dir}/sonar-jacoco-module.xml"/>
<import file="nbproject/build-impl.xml"/>
9、用以下内容替换每个套件的build.xml的内容:
<description>Builds the module suite otherSuite.</description>
<property file="nbproject/private/platform-private.properties"/>
<property file="${user.properties.file}"/>
<import file="${nbplatform.default.harness.dir}/sonar-jacoco-suite.xml"/>
<import file="nbproject/build-impl.xml"/>
Jenkins
在“管理Jenkins->管理插件”中,进入可用列表并安装(如果尚未存在)以下插件:
- JaCoCo
 - Mercurial or Subversion
 - Sonar
 
如果您在防火墙或代理后面,并且在配置网络设置时遇到问题,可以随时从此处手动下载并安装它们。在这种情况下,请记住还要先下载每个插件的依赖项。
在“管理Jenkins->配置系统”中,检查是否正确安装了所有插件,请参见以下屏幕截图以获取示例(将文件夹替换为适合您的文件夹):




创建一个新的自由样式项目,配置您的首选项的版本控制,然后在“构建”面板中添加以下三个“ Invoce Ant”任务:

在“构建后操作”面板中添加新的“记录Jacoco覆盖率报告”,其配置如下:

Sonar
按照此脚本创建数据库,并选择运行此查询以使连接正常工作:
GRANT ALL PRIVILEGES ON 'sonar'.* TO 'sonar'@'localhost';
进入声纳的配置文件(sonar.properties)并启用MySQL,该文件位于安装的conf文件夹中:
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
在声纳的配置中,如果需要与Java 8兼容,请更新Java插件
技术类文章精选
- java一行代码打印心形
 - Linux性能监控软件netdata中文汉化版
 - 接口测试代码覆盖率(jacoco)方案分享
 - 性能测试框架
 - 如何在Linux命令行界面愉快进行性能测试
 - 图解HTTP脑图
 - 将swagger文档自动变成测试代码
 - 五行代码构建静态博客
 - 基于java的直线型接口测试框架初探
 - JUnit中用于Selenium测试的中实践
 
非技术文章精选
- 为什么选择软件测试作为职业道路?
 - 写给所有人的编程思维
 - 成为优秀自动化测试工程师的7个步骤
 - 手动测试存在的重要原因
 - 成为自动化测试的7种技能
 - 自动化和手动测试,保持平衡!
 - 自动化测试生命周期
 - 如何在DevOps引入自动化测试
 
Java 8,Jenkins,Jacoco和Sonar进行持续集成的更多相关文章
- 使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(二)
		
前言 上一篇随笔Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(一)介绍maven和nexus的环境搭建,以及如何使用maven和nexus统一管理库 ...
 - Jenkins+maven+git+sonar 系统持续集成&代码单測管理
		
Jenkins+maven+git+sonar 系统持续集成&代码单測管理 Jenkins的安装 Jenkins是基于Java开发的一种持续集成工具,用于监控持续反复的工作.功能包含: 1.持 ...
 - Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(二)
		
上一篇随笔Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(一)介绍maven和nexus的环境搭建,以及如何使用maven和nexus统一管理库文件和版本,以 ...
 - 使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境
		
前言 但凡一个略有规模的项目都需要一个持续集成环境的支撑,为什么需要持续集成环境,我们来看一个例子.假如一个项目,由A.B两位程序员来协作开发,A负责前端模块,B负责后端模块,前端依赖后端.A和B都习 ...
 - Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境
		
使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(一) 2015-01-14 20:28 by 飘扬的红领巾, 4322 阅读, 5 评论, 收藏, 编辑 ...
 - 使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(一)
		
前言 但凡一个略有规模的项目都需要一个持续集成环境的支撑,为什么需要持续集成环境,我们来看一个例子.假如一个项目,由A.B两位程序员来协作开发,A负责前端模块,B负责后端模块,前端依赖后端.A ...
 - Jenkins+Gitlab CE+Robot Framework持续集成
		
环境 Ubuntu 14.04.3 LTS Desktop 前提 1.在本地能执行测试脚本(pybot yourTestSuit.txt),本文不讲解如何学习使用RF框架 2.已有Gitlab环境,本 ...
 - 使用Jenkins+Calabash+Cocoapods搭建iOS持续集成环境
		
使用jenkins+calabash+cocoapods搭建ios持续集成环境 持续集成 持续集成到底是什么呢?依据敏捷大师Martin Fowler的定义: 持续集成是一种软件开发实践. 在持续集成 ...
 - 构建gitlab+Jenkins+harbor+kubernetes的DevOps持续集成持续部署环境
		
构建gitlab+Jenkins+harbor+kubernetes的DevOps持续集成持续部署环境 整个环境的结构图. 一.准备工作 gitlab和harbor我是安装在kubernetes集群外 ...
 
随机推荐
- java8的捕获多个异常的一个写法
			
这是按intellij idea的提示知道的, 可以写成 catch(xxxException | yyyException | zzzException e){ } 这样的形式,对几个不同的异常使用 ...
 - C# 中代码执行 ping 操作
			
在代码中可以通过调用 System.Net.NetworkInformation 命名控件下的 Ping 类的 Send() 方法来实现,代码如下: var ping = new System.Net ...
 - java之类的构造方法
			
构造器的特征: 具有和类相同的名称: 不声明返回值的类型: 不能被static.final.synchronized.abstract.native修饰,不能有return语句返回值: 构造器的作用: ...
 - C/C++ 中 `printf` 格式化
			
作为强类型静态语言,类型不仅规定了可以对数据进行的操作,还决定了应该怎样在 printf 中输出. printf 的签名是: int printf ( const char * format, ... ...
 - 爬虫模拟有道字典进行翻译,还发现了一条好玩的js
			
08.14自我总结 爬虫模拟有道字典进行翻译 一.代码 import requests from lxml.html import etree # headers= { # 'User-Agent': ...
 - Java生鲜电商平台-交易对账以及跟商家对账的思考
			
Java生鲜电商平台-交易对账以及跟商家对账的思考 说明:对于任何一家电商而言,资金的安全尤为重要,在资金管理过程中,涉及到交易订单的对账以及商家的对账,那i么如何来保证对账的高效与准确呢? 公司在搭 ...
 - php反序列化漏洞绕过魔术方法 __wakeup
			
0x01 前言 前天学校的ctf比赛,有一道题是关于php反序列化漏洞绕过wakeup,最后跟着大佬们学到了一波姿势.. 0x02 原理 序列化与反序列化简单介绍 序列化:把复杂的数据类型压缩到一个字 ...
 - Java - IO 扫描流:Scanner
			
IO_扫描流:Scanner 在改进输出功能不足方面提供了打印流(PrintSream):利用BufferedReader类(缓冲输入流)解决了大文本数据的输入和读取操作,但是BufferedRead ...
 - SAP depreciation key config
			
正常折旧 Configure 1.分配总帐科目 spro进入后台配置 –> Financial Accounting(New) –> Asset Accounting –> Depr ...
 - Android Studio 3.0 及以上版本使用技巧总结
			
1.更新Android Studio后下载Gradle文件的技巧 更新到3.0版本后,可能会出现创建新项目一直停留在如下图的界面: 选择等待?不知道要等到什么时候,这时候怎么办呢?显然,不能一直等待下 ...