Grails 代码覆盖
在本指南中,您将学习如何使用 Clover 提高代码覆盖率。
作者:Sergio del Amo
Grails 版本 4.0.1
1 Grails 培训
Grails 培训 - 由创作和积极维护 Grails 框架的人员开发和交付!。
2 开始使用
Atlassian Clover 向 Java 和 Groovy 开发人员提供代码覆盖率分析的可靠来源。
自 2017 年 4 月 11 日起,Clover 已成为开源软件。
Grails 3 使用 Gradle 构建系统来完成构建相关任务,如编译、运行测试和生成项目的二进制分发版。
在本指南中,我们将安装一个 Gradle 来获取 Grails 应用程序的代码覆盖率。
2.1 所需环境
如需完成本指南,您将需要以下环境
-
一些闲暇时间
-
一个不错的文本编辑器或 IDE
-
安装了 JDK 1.8 或更高版本,并正确配置了
JAVA_HOME
2.2 如何完成本指南
如需开始,请执行以下操作
-
下载并解压源代码
或
-
克隆 Git 存储库
git clone https://github.com/grails-guides/grails-code-coverage.git
Grails 指南存储库有两个文件夹
-
initial
初始项目。通常是一个简单的 Grails 应用,包含一些附加代码,以便您能快速上手。 -
complete
完整的示例。它是按照指南中给定的步骤进行操作并在initial
文件夹中应用这些更改的结果。
如需完成本指南,请转至 initial
文件夹
-
在
grails-guides/grails-code-coverage/initial
中执行cd
并按照下一节中的说明进行操作。
如果cd 到grails-guides/grails-code-coverage/complete ,你即可直接跳转到完整的示例 |
3 编写应用程序
3.1 Gradle Clover 插件
我们将使用 Gradle Clover 插件使用 Clover 生成代码覆盖率报告。
我们将创建 gradle 文件,集中放置 Clover 配置
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-clover-plugin:2.1.1'
}
}
apply plugin: 'com.bmuschko.clover'
dependencies {
clover 'org.openclover:clover:4.4.1'
}
clover {
licenseLocation = File.createTempFile('clover', '.license').absolutePath (1)
excludes = ['**/Application.groovy', (2)
'**/BootStrap.groovy',
'**/UrlMappings.groovy',
'**/*GrailsPlugin.groovy',
'**/*Mock.groovy',
]
testIncludes = ['**/*Spec.groovy'] (3)
report { (4)
html = true
xml = true
}
}
1 | 虽然 Clover 是开放源代码的,但你需要创建一个虚拟许可证文件。 |
2 | 我们不希望某些文件污染我们的代码覆盖率报告。 |
3 | 我们希望将 Spock 规范包含为测试文件。 |
4 | 我们希望获得 XML 和 HTML 两种格式的报告 |
我们希望从 ROOT build.gradle
中引用此文件
buildscript {
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
classpath "com.bertramlabs.plugins:asset-pipeline-gradle:3.0.11"
classpath "org.grails.plugins:hibernate5:7.0.0"
classpath 'com.bmuschko:gradle-clover-plugin:2.2.4' (1)
}
}
version "0.1"
group "grails.code.coverage"
apply plugin:'groovy'
apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"org.grails.grails-gsp"
apply plugin:"com.bertramlabs.asset-pipeline"
apply from: "${project.projectDir}/gradle/clover.gradle" (2)
repositories {
maven { url "https://repo.grails.org/grails/core" }
}
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
compile "org.springframework.boot:spring-boot-starter-logging"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "org.grails:grails-core"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"
compile "org.grails:grails-logging"
compile "org.grails:grails-plugin-rest"
compile "org.grails:grails-plugin-databinding"
compile "org.grails:grails-plugin-i18n"
compile "org.grails:grails-plugin-services"
compile "org.grails:grails-plugin-url-mappings"
compile "org.grails:grails-plugin-interceptors"
compile "org.grails.plugins:cache"
compile "org.grails.plugins:async"
compile "org.grails.plugins:scaffolding"
compile "org.grails.plugins:events"
compile "org.grails.plugins:hibernate5"
compile "org.hibernate:hibernate-core:5.4.0.Final"
compile "org.grails.plugins:gsp"
compile "io.micronaut:micronaut-inject-groovy"
console "org.grails:grails-console"
profile "org.grails.profiles:web"
runtime "org.glassfish.web:el-impl:2.1.2-b03"
runtime "com.h2database:h2"
runtime "org.apache.tomcat:tomcat-jdbc"
runtime "com.bertramlabs.plugins:asset-pipeline-grails:3.0.11"
testCompile "org.grails:grails-gorm-testing-support"
testCompile "org.grails:grails-web-testing-support"
}
bootRun {
jvmArgs(
'-Dspring.output.ansi.enabled=always',
'-noverify',
'-XX:TieredStopAtLevel=1',
'-Xmx1024m')
sourceResources sourceSets.main
}
assets {
minifyJs = true
minifyCss = true
}
1 | 将插件添加为构建脚本依赖项 |
2 | 使用 Clover 配置应用构建文件。 |
3.2 代码和测试
我们有一个领域类
package demo
class Person {
String name
boolean active
}
我们还有一个服务,在其中封装了针对上一个领域类的 GORM 查询。
package demo
import grails.gorm.services.Service
import grails.gorm.transactions.ReadOnly
@Service(Person)
interface PersonGormService {
@ReadOnly
List<Person> findAllByActive()
}
我们有一个 Groovy POJO。
package demo
import groovy.transform.Canonical
import groovy.transform.CompileStatic
@Canonical
@CompileStatic
class Name {
String firstName
String lastName
}
该应用程序的业务逻辑位于 NameService
中,它猜测每个 Person
实例的firstName
和 lastName
。
package demo
import groovy.transform.CompileStatic
@CompileStatic
class NameService {
PersonGormService personGormService
List<Name> findAllPersonNames() {
personGormService.findAllByActive().collect { Person person ->
nameWithFullName(person.name)
}
}
Name nameWithFullName(String fullname) {
if ( fullname.contains('del ') ) {
return nameWithSeparator(fullname, 'del')
}
return nameWithSeparator(fullname, ' ')
}
Name nameWithSeparator(String fullname, String separator) {
String firstName
String lastName
String[] arr = fullname.split(separator)
if ( arr.length > 0 ) {
firstName = "${arr[0]}${separator}".toString()
int from = firstName.length()
lastName = fullname.substring(from, fullname.length())
} else {
firstName = fullname
}
new Name(firstName: firstName?.trim(), lastName: lastName?.trim())
}
}
我们为此服务编写了测试
package demo
import grails.testing.services.ServiceUnitTest
import spock.lang.Specification
class NameServiceSpec extends Specification implements ServiceUnitTest<NameService> {
def "findAllPersonNames differentiates between names containing the substring 'del'"() {
given:
service.personGormService = Stub(PersonGormService) {
findAllByActive() >> [
// new Person(name: 'Sergio del Amo', active: true), (1)
new Person(name: 'Graeme Rocher', active: true),]
}
when:
List<Name> names = service.findAllPersonNames()
then:
names.each { Name name ->
assert [
new Name(firstName: 'Sergio del', lastName: 'Amo'),
new Name(firstName: 'Graeme', lastName: 'Rocher')
].contains(name)
}
}
}
1 | 取消此行的注释以增加代码覆盖率。 |
4 运行应用程序
为了生成代码覆盖率报告,请使用 ./gradlew cloverGenerateReport
命令,这将在以下位置生成报告:build/reports/clover/html/index.html
浏览你的报告并改进项目覆盖率