fitnesse二次开发

你离开我真会死。 提交于 2019-12-23 01:40:26

自动化测试,首先想到的就是fitnesse。但是毕竟fitnesse功能优先,在自动化测试中,会遇到瓶颈。这个时候就需要对fitnesse进行二次开发。fitnesse不但有可以直接部署运行的jar包,在github上也可以下载到源代码。
源码是用gradle工具进行构建的。
Github下载地址https://github.com/unclebob/fitnesse.git

一、Gradle安装

我使用的是IDEA 2017,对应的gradle版本是3.5,安装过程很简单,网上一查便知。完成后需要配置系统环境变量:GRADLE_HOME、GRADLE_USER_HOME以及path变量。
GRADLE_HOME环境变量
GRADLE_USER_HOME环境变量
Path变量
Path变量
打开cmd命令行,然后运行gradle -v,会显示gradle的信息,则表示安装成功。
gradle -v命令

二、IDEA导入fitnesse项目

打开idea,导入项目后,需要配置很多信息。gradle目录下的gradle-wrapper.properties中改成版本3.5

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-3.5-bin.zip
zipStorePath=wrapper/dists

build.gradle文件是利用gradle进行项目构建的核心配置文件,以下是经过我修改后可行的配置。

buildscript {
    repositories {
      mavenCentral()
    }
    dependencies {
      classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.1.9'
    }
}

plugins {
  id 'java'
  id "maven-publish"
  id "com.jfrog.bintray" version "1.8.4"
  id "com.github.ben-manes.versions" version "0.20.0"
}

apply plugin: "info.solidsoft.pitest"
version = new Date().format('yyyyMMdd')
println "Building FitNesse v${project.version}..."

repositories {
  mavenCentral()
}

configurations {
  lesscss
  optional
  compile {
    transitive = false
    extendsFrom optional
  }
  runtime {
    transitive = false
  }
}

sourceSets {
  main {
    java.srcDir 'src'
    resources.srcDir 'src'
    output.resourcesDir output.classesDir
  }
  test {
    java.srcDir 'test'
  }
}

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

dependencies {
  compile "org.htmlparser:htmlparser:2.1"
  compile "org.htmlparser:htmllexer:2.1"
  compile ("org.apache.velocity:velocity-engine-core:2.0") {
    exclude group:"org.apache.commons", module: "commons-lang3"
    exclude group: 'org.slf4j', module: 'slf4j-api'
  }
  compile "org.apache.commons:commons-lang3:3.8.1"
  compile "org.slf4j:slf4j-api:1.7.25"
  compile "org.slf4j:slf4j-jdk14:1.7.25"
  compile "org.json:json:20180813"
  compile "com.googlecode.java-diff-utils:diffutils:1.3.0"
  optional "org.apache.ant:ant:1.10.5"
  optional "junit:junit:4.12"

  testCompile "junit:junit:4.12"
  testCompile "org.mockito:mockito-core:2.23.4"
  testCompile "org.hamcrest:hamcrest-all:1.3"
  testCompile "net.javacrumbs.json-unit:json-unit:2.2.0"

  compileOnly files('lib/joda-time-2.3.jar')

  lesscss "org.mozilla:rhino:1.7.10"
}

task fitNesseVersion {
  def versionFile = new File("${sourceSets.main.output.resourcesDir}/META-INF/FitNesseVersion.txt")
  versionFile.parentFile.mkdirs()
  versionFile.text="v${version}"
}

task compileBootstrap(type: LessCompiler) {
  inputDir file('src/fitnesse/resources/bootstrap/less')
  mainLessFile = 'fitnesse-bootstrap.less'
  cssFile file("${sourceSets.main.output.resourcesDir}/fitnesse/resources/bootstrap/css/fitnesse-bootstrap.css")
  classpath configurations.lesscss
}

task createUpdateLists(type: WikiFileListBuilderTask) {
  outputDirectory = "${sourceSets.main.output.resourcesDir}/Resources"

  files = {
    // Make sure only files in version control are added to the default wiki contents
    "git ls-files FitNesseRoot".execute().text.readLines()
  }

  doNotReplaceFiles = [
    "FitNesseRoot/content.txt",
    "FitNesseRoot/properties.xml",
    "FitNesseRoot/FrontPage/content.txt",
    "FitNesseRoot/FrontPage/properties.xml",
    "FitNesseRoot/PageHeader/content.txt",
    "FitNesseRoot/PageHeader/properties.xml",
    "FitNesseRoot/PlugIns/content.txt",
    "FitNesseRoot/PlugIns/properties.xml",
    "FitNesseRoot/PageFooter/content.txt",
    "FitNesseRoot/PageFooter/properties.xml",
    "FitNesseRoot/TemplateLibrary/content.txt",
    "FitNesseRoot/TemplateLibrary/properties.xml",
    "FitNesseRoot/TemplateLibrary/StaticPage/content.txt",
    "FitNesseRoot/TemplateLibrary/StaticPage/properties.xml",
    "FitNesseRoot/TemplateLibrary/SuitePage/content.txt",
    "FitNesseRoot/TemplateLibrary/SuitePage/properties.xml",
    "FitNesseRoot/TemplateLibrary/TestPage/content.txt",
    "FitNesseRoot/TemplateLibrary/TestPage/properties.xml" ]
}

processResources.dependsOn "fitNesseVersion", "compileBootstrap", "createUpdateLists"

task copyRuntimeLibs(type: Copy) {
  into "lib"
  from configurations.runtime
}

test {
  dependsOn copyRuntimeLibs
  maxParallelForks 1
}

pitest {
  targetClasses = ['fit.*', 'fitnesse.*']
  pitestVersion = "1.4.3"
  threads = 1 // We can not deal with parallel execution yet
  outputFormats = ['XML', 'HTML']
}

task run(type: JavaExec) {
  dependsOn classes, copyRuntimeLibs
  classpath = sourceSets.main.runtimeClasspath
  main "fitnesseMain.FitNesseMain"
  args "-p", "8001", "-e", "0"
}

jar {
  dependsOn createUpdateLists
  from {
    //添加依懒到打包文件
    configurations.runtime.collect{zipTree(it)}
  }
  into('Resources') {
    from('.') {
      include createUpdateLists.wikiFiles as String[]
    }
  }
  duplicatesStrategy = 'exclude'
  manifest {
    attributes("Main-Class": "fitnesseMain.FitNesseMain",
      "Implementation-Version": version)
  }
}

task standaloneJar(type: Jar) {
  baseName = 'fitnesse'
  classifier = 'standalone'
  from {
    (configurations.compile - configurations.optional).collect { zipTree(it) }
  } {
    exclude 'META-INF/**'
  }
  from jar.outputs.files.collect {
    zipTree(it)
  }
  manifest {
    attributes("Main-Class": "fitnesseMain.FitNesseMain",
        "Implementation-Version": version)
  }
}

task slimJar(type: Jar) {
  baseName = 'fitnesse'
  classifier = 'slim'
  from { jar.outputs.files.collect { zipTree(it) } }
    {
    include 'fitnesse/html/*.class'
    include 'fitnesse/slim/**/*.class'
    include 'fitnesse/socketservice/*.class'
    include 'util/*.class'
    include 'fitnesse/util/StringUtils.class'
  }
  manifest {
    attributes("Implementation-Version": version)
  }
}

task acceptanceTest(type: JavaExec) {
  mustRunAfter test
  onlyIf { test.didWork }
  classpath = standaloneJar.outputs.files
  main "fitnesseMain.FitNesseMain"
  args "-o", "-c", "FitNesse.SuiteAcceptanceTests?suite&format=text"
}

check.dependsOn acceptanceTest

task javadocJar(type: Jar) {
  mustRunAfter check
  classifier = 'javadoc'
  from javadoc
}

task sourcesJar(type: Jar) {
  mustRunAfter check
  classifier = 'sources'
  from sourceSets.main.allSource
}

task releaseTag(type: Exec) {
  commandLine 'git', 'tag', project.version
  doLast {
    println "Tagged release ${project.version}"
  }
}

task publishTag(type: Exec) {
  commandLine 'git', 'push', '--tags'
  shouldRunAfter releaseTag
}

task prepareSnapshotRepo {
    bintray.pkg.repo = 'edge'
}

task prepareReleaseRepo {
    bintray.pkg.repo = 'release'
}

bintrayUpload.mustRunAfter prepareSnapshotRepo, prepareReleaseRepo

task snapshotRelease {
  dependsOn prepareSnapshotRepo, bintrayUpload
}

task release {
  dependsOn releaseTag, prepareReleaseRepo, bintrayUpload, publishTag
}

clean {
  delete "lib"
}

publishing {
  publications {
    FitNesseRelease(MavenPublication) {
      from components.java
      artifact sourcesJar
      artifact javadocJar
      artifact standaloneJar
      artifact slimJar
      groupId 'org.fitnesse'
      artifactId 'fitnesse'
      pom.withXml {
        asNode().get('version') + {
          resolveStrategy = Closure.DELEGATE_FIRST
          name('FitNesse')
          description('The fully integrated standalone wiki, and acceptance testing framework.')
          url('http://fitnesse.org')
          packaging('jar')
        }
        asNode().append(pomLicenses())
        asNode().append(pomScm())
        asNode().append(pomDevelopers())

        // Clean up scope entries added by the pom generator:
        asNode().dependencies.'*'.findAll() {
          if (project.configurations.optional.allDependencies
              .find { dep -> dep.name == it.artifactId.text()}) {
            def xmlOptional = it.optional[0]
            if ( !xmlOptional ) {
              xmlOptional = it.appendNode('optional')
            }
            xmlOptional.value = 'true'
          }
        }
      }
    }
  }
}

bintray {
  user = System.getenv("BINTRAY_USER") ?: 'Define your Bintray user name in BINTRAY_USER'
  key = System.getenv("BINTRAY_API_KEY") ?: 'Define your Bintray BINTRAY_API_KEY'
  publications = ['FitNesseRelease']
  publish = true
  pkg {
    name = 'fitnesse'
    userOrg = 'fitnesse'
    licenses = ['CPL-1.0']
    websiteUrl = 'http://fitnesse.org'
    vcsUrl = 'https://github.com/unclebob/fitnesse.git'
    publicDownloadNumbers = true
    githubRepo = 'unclebob/fitnesse'
    version {
      name = project.version
      desc = "FitNesse release ${project.version}"
      vcsTag = project.version
      gpg {
        sign = true
      }
    }
  }
}

wrapper {
  gradleVersion = '5.3.1'
}


def pomLicenses() {
  new NodeBuilder().licenses {
    license {
      name 'Common Public License version 1.0'
      url 'http://www.opensource.org/licenses/cpl1.0'
      distribution 'repo'
    }
  }
}

def pomScm() {
  new NodeBuilder().scm {
    connection 'scm:git:git://github.com/unclebob/fitnesse.git'
    developerConnection 'scm:git:git@github.com:unclebob/fitnesse.git'
    url 'scm:git:http://github.com/unclebob/fitnesse'
  }
}

def pomDevelopers() {
  new NodeBuilder().developers {
    developer {
      id 'unclebob'
      name 'Robert C. Martin'
      email 'unclebob@cleancoder.com'
    }
  }
}

修改完成后,refresh一下gradle项目,会根据build.gradle文件的配置,对项目进行以下更新。
refresh gradle配置
现在运行一下,可能会发现有空指针的现象,定位后发现,缺少Resources文件夹。所以需要导入一下这个资源文件夹。可以直接导入fitnesse-standalone.jar中的Resources文件夹,这样可以解决空指针的问题。另外,src/fitnesse/resources/bootstrap下没有css样式文件夹,这个也需要从fitnesse-standalone.jar中导入进来。
缺少的css样式
fitnesse源码构建
缺少的Resources文件目录
fitnesse源码构建

三、运行和构建

踩了一系列的坑之后,终于可以运行了,运行的结果正是我们想要看到的结果。
fitnesse界面
然后需要打包发布,这里遇到很多问题,可能打包成功后,运行报错。有错误的时候,百度不到也很正常,要善于思考,定会解决。刚开始不是很顺利,运行jar包缺少对应的模块,之后改了一下build.gradle的配置
,添加了下面一段话,就成功了。
修改fitnesse配置文件
打包的时候,需要进入gradle工程的主目录下,也就是build.gradle文件所在的目录下。运行命令:gradle jar,打包完成后,会在主目录下的build/libs下生成我们需要的jar文件。
gradle打包jar文件生成路径

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!