我正在尝试运行以下 CucumberWithSerenity TestRunner 类:
import net.serenitybdd.cucumber.CucumberWithSerenity;
import cucumber.api.CucumberOptions;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
//@RunWith(Cucumber.class)
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(format = {"pretty"}, monochrome=true)
public class TestRunner {
public static void main(String[] args) throws Exception {
System.out.println("TestRunner...");
JUnitCore junit = new org.junit.runner.JUnitCore() ;
try {
throw new Exception();
} catch(Exception e) {
// code to handle the exception
Result result = junit.run(TestRunner.class);
for (Failure failure : result.getFailures())
{
System.out.println(failure.toString());
}
}
}
}
作为 java -jar App.jar ,上面的 main 是使用 gradle 进行 jar 化的。
但是,我收到以下错误:
initializationError(serenity.TestRunner): net/thucydides/core/guice/Injectors
没有使用 CucumberWithSerenity,我不确定应该如何进行初始化。
这个 main() 类背后的想法是制作一个包含所有 Serenity 测试的 jar 文件,并在任何地方运行它们。
这是 build.gradle
import groovy.io.FileType
import groovy.text.Template
apply plugin: 'groovy'
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'TestRunner'
//jar {
// manifest {
// attributes 'Main-Class': 'cucumber.api.cli.Main'
// }
//}
def cucumberVersion = "1.2.4"
buildscript {
repositories { maven{ url "http://${nexus}/nexus/content/groups/public/"
} }
dependencies { classpath("net.serenity-bdd:serenity-gradle-plugin:1.0.56") }
}
repositories {
maven { url "http://${nexus}/nexus/content/groups/public/"
}
flatDir {
dirs 'test/resources/libs'
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'net.serenity-bdd.aggregator'
configurations {
//outdated dependency, use hamcrest-core:1.3
testCompile.exclude group: 'org.hamcrest', module: 'hamcrest-all'
cucumberRuntime {
extendsFrom testRuntime
}
//cucumber
}
//build.dependsOn cucumber
dependencies {
testCompile 'org.hamcrest:hamcrest-core:1.3'
testCompile 'com.jayway.restassured:rest-assured:2.7.0'
testCompile 'net.serenity-bdd:serenity-rest-assured:1.1.21'
testCompile 'net.serenity-bdd:serenity-junit:1.1.21'
testCompile 'net.serenity-bdd:serenity-core:1.1.21'
testCompile 'net.serenity-bdd:serenity-cucumber:1.1.1'
testCompile 'org.jbehave:jbehave-core:4.0.4'
testCompile 'net.serenity-bdd:serenity-jbehave:1.1.0'
testCompile 'de.codecentric:jbehave-junit-runner:1.1.0'
testCompile 'junit:junit:4.2'
testCompile 'cglib:cglib-nodep:3.2.0'
testCompile 'org.assertj:assertj-core:3.1.0'
testCompile 'org.slf4j:slf4j-simple:1.7.12'
compile 'com.jayway.jsonpath:json-path:2.0.0'
compile 'com.github.groovy-wslite:groovy-wslite:1.1.0'
compile 'org.springframework:spring-web:3.2.8.RELEASE'
testCompile 'org.apache.activemq:activemq-all:5.12.0'
testCompile 'org.mongodb:mongo-java-driver:2.11.4'
testCompile 'com.fasterxml.jackson.core:jackson-core:2.4.4'
testCompile 'com.fasterxml.jackson.core:jackson-databind:2.4.4'
testCompile "info.cukes:cucumber-junit:$cucumberVersion"
testCompile "info.cukes:cucumber-groovy:$cucumberVersion"
testCompile 'net.serenity-bdd:serenity-cucumber:1.0.17'
compile files('src/test/libs/junit-4.2.jar')
runtime files('src/test/libs/junit-4.2.jar')
compile files('src/test/libs/hamcrest-core-1.3.jar')
runtime files('src/test/libs/hamcrest-core-1.3.jar')
compile files('src/test/libs/cucumber-junit-1.2.4.jar')
runtime files('src/test/libs/cucumber-junit-1.2.4.jar')
compile files('src/test/libs/cucumber-java-1.2.4.jar')
runtime files('src/test/libs/cucumber-java-1.2.4.jar')
compile files('src/test/libs/cucumber-core-1.2.4.jar')
runtime files('src/test/libs/cucumber-core-1.2.4.jar')
//compile files('src/test/libs/serenity-cucumber-1.0.2.jar')
//runtime files('src/test/libs/serenity-cucumber-1.0.2.jar')
compile files('src/test/libs/cucumber-jvm-deps-1.0.5.jar')
runtime files('src/test/libs/cucumber-jvm-deps-1.0.5.jar')
compile files('src/test/libs/gherkin-2.12.2.jar')
runtime files('src/test/libs/gherkin-2.12.2.jar')
compile files('src/test/libs/cucumber-reporting-2.0.0.jar')
runtime files('src/test/libs/cucumber-reporting-2.0.0.jar')
compile files('src/test/libs/thucydides-core-0.9.125.jar')
runtime files('src/test/libs/thucydides-core-0.9.125.jar')
}
task cucumber() {
dependsOn assemble
doLast {
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime
args = ['--plugin', 'pretty', '--glue', 'src/test/java', 'src/test/resources', 'src/main/java']
//classpath = configurations.cucumber
}
}
}
test{
def fileMap = new TreeMap<String, File>();
def redirectionMap = new TreeMap<String, String>();
def blacklist = new ArrayList<String>();
blacklist.add("net.thucydides.core.reflection.StackTraceAnalyser");
onOutput { descriptor, event ->
def messageBlacklisted = false;
for(String blacklistedString : blacklist) {
if(event.message.contains(blacklistedString)){
messageBlacklisted=true;
}
}
//Gradle Test Executor 1
def executor = descriptor;
while(executor.getClassName() != null)
{
executor = executor.getParent();
}
def originalKey = executor.getName();
def key = originalKey;
def redirectionMessages = [/TEST STARTED: (.*)$/];
for(def regex : redirectionMessages)
{
def result = (event.message =~ regex);
if(result.size()>=1)
{
def redirectedLocation = result[0][1];
redirectionMap.put(key, redirectedLocation);
logger.lifecycle("Redirecting "+key+"->"+redirectedLocation);
}
}
def depth = 0;
while(redirectionMap.containsKey(key) && depth < 10)
{
depth+1;
key = redirectionMap.get(key);
}
//key is still gradle test executor, may as well use something more useful
if(key.equals(originalKey))
{
key = descriptor.getClassName();
}
def streamName = key.replaceAll("[^a-zA-Z0-9\\._]+", "_");
if(!messageBlacklisted) {
if(!fileMap.containsKey(streamName)) {
def outputFile = createSerenityLogFile(streamName+".txt");
fileMap.put(streamName, outputFile);
}
def resultingMessage = preprocessOutput(event.message)
fileMap.get(streamName) << resultingMessage;
}
}
}
public String preprocessOutput(String originalMessage)
{
java.text.DateFormat dateFormat = new java.text.SimpleDateFormat("HH:mm:ss");
String timestamp = dateFormat.format(new java.util.Date());
String[] splitSegments = originalMessage.split("[\r\n]+");
Collection<String> transformedSegments = splitSegments.collect{line->
timestamp+"\t"+line+"\n";
};
String resultingMessage = transformedSegments.iterator().join("");
return resultingMessage;
}
public File createSerenityLogFile(String fileName){
def logFolder = new File(new File(project.rootDir, project.serenity.outputDirectory), "logs");
createDirectory(logFolder);
def outputFile = new File(logFolder, fileName);
deleteFile(outputFile);
createFile(outputFile);
return outputFile;
}
tasks.test.doFirst {
logging.captureStandardOutput LogLevel.INFO
logger.lifecycle("Transfering gradle properties to system properties...");
systemProperty 'cucumber.options', System.getProperty('cucumber.options', '')
if(project.hasProperty("firefox.profile.path"))
systemProperty 'firefox.profile.path', project.getProperty('firefox.profile.path')
setSystemProperty "webdriver.base.url", "http://${ftWebHost}:8080"
if(project.hasProperty("ftWebHost")){
systemProperty "restassured.base.url", project.getProperty("ftWebHost")
}
//This will set the webdriver url and the restAssured url
systemProperty "restassured.base.url", "${ftWebHost}"
setSystemProperty "webdriver.base.url", "http://${ftWebHost}:8080"
setSystemProperty "jmsBrokerURL", "tcp://${ftWebHost}:61616"
if (project.hasProperty("apiDebugOutput")) {
systemProperty "debug.api.testing", "${apiDebugOutput}"
}
if(project.hasProperty("ftWebPort")){
systemProperty "restassured.base.port", "${ftWebPort}"
}
if(project.hasProperty("ftWebSecure")){
systemProperty "restassured.secure.connection", "${ftWebSecure}"
}
if(project.hasProperty("payURL"))
setSystemProperty "pay.url", "${payURL}"
systemProperty "pay.url", "${payURL}"
if(project.hasProperty("formTHost") && project.hasProperty("internalAppFTHost")) {
setSystemProperty "external.host", "${formI90FTHost}/efile/login"
systemProperty "external.host", "${formTHost}/file/login"
setSystemProperty "internal.host", "${internalAppFTHost}/InternalApp/login"
systemProperty "internal.host", "${internalAppFTHost}/InternalApp/login"
}
if(project.hasProperty("ftWebPort") && project.hasProperty("formI90FTHost") && project.hasProperty("internalAppFTHost")) {
setSystemProperty "external.host", "${formI90FTHost}:${ftWebPort}/efile/login"
systemProperty "external.host", "${formI90FTHost}:${ftWebPort}/efile/login"
setSystemProperty "internal.host", "${internalAppFTHost}:${ftWebPort}/InternalApp/login"
systemProperty "internal.host", "${internalAppFTHost}:${ftWebPort}/InternalApp/login"
}
println "Overriding serenity properties for child jvms based on system properties (takes precedence over serenity.properties)..."
net.thucydides.core.util.SystemEnvironmentVariables environmentVariables = new net.thucydides.core.util.SystemEnvironmentVariables();
Map<String, net.thucydides.core.ThucydidesSystemProperty> propertyNameMap = new TreeMap<String, net.thucydides.core.ThucydidesSystemPrope
rty>();
for(net.thucydides.core.ThucydidesSystemProperty property : net.thucydides.core.ThucydidesSystemProperty.values()) {
String key = property.getPropertyName().replaceAll("thucydides.","serenity.");//withSerenityPrefix() method
propertyNameMap.put(key, property);
}
for(String key : propertyNameMap.keySet()){
net.thucydides.core.ThucydidesSystemProperty property = propertyNameMap.get(key);
if(property.isDefinedIn(environmentVariables)) {
String value = property.from(environmentVariables);
println "(O)${key}=${value}"
systemProperty key, value
}
else {
println "( )${key}"
}
}
if(project.hasProperty("maxParallelForks")) {
int forks = project.getProperty("maxParallelForks") as int;
println "Running up to ${forks} test suites in parallel";
maxParallelForks = forks;
}
}
public void setSystemProperty(String key, String value){
System.setProperty(key, value);
println "Set system property "+key+"="+value;
}
task cucumberMonkey(dependsOn: 'compileTestJava', type:JavaExec){
doFirst{
println("Executing cucumber monkey");
classpath = sourceSets.main.output + sourceSets.test.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath
main = 'gov.dhs.uscis.elis2.serenity.utils.cucumbermonkey.CucumberMonkeyRunner'
standardOutput = new FileOutputStream(createSerenityLogFile("CucumberMonkey.txt"));
}
}
task generateCucumberTestSuites (dependsOn: 'processTestResources') {
File root = buildFile.getParentFile();//assumes build.gradle is in root directory
File featureTemplatePath = new File(root, "FeatureFile.template");
File cucumberTemplatePath = new File(root, "CucumberTestSuite.template");
File featureDirectory = new File(root, "src/test/resources/features/");
File outputFeatureDirectory = new File(root, "src/test/resources/autogenerated/");
File testSuitePath = new File(root,"src/test/java/serenity/")
String testSuitePackage = "serenity"
String[] glue = ["serenity.parallel"]
String testSuiteRegex = /CucumberTestSuite\d+.java/
String featureTestRegex = /.*\.feature/
Template cucumberTemplate = readTemplate(cucumberTemplatePath);
Template featureTemplate = readTemplate(featureTemplatePath);
def featureProp = "";
if(project.hasProperty("features")) {
featureProp = features;
}
featureProp = featureProp.split(",");
Set<File> matchedFeatures = filterMatchedFeatures(matchFiles(featureDirectory, featureTestRegex, true), featureProp)
generateCucumberTestSuites(cucumberTemplate, featureTemplate, matchedFeatures, testSuitePath, testSuitePackage, glue, outputFeatureDirect
ory, testSuiteRegex);
}
public Set<File> filterMatchedFeatures(Set<File> files, String[] features) {
if(features.length == 0)
return files;
Set<File> matchedFiles = new TreeSet<File>();
for(File f : files) {
for(String feature : features) {
if(f.getName().contains(feature.trim())) {
matchedFiles.add(f);
break;
}
}
}
return matchedFiles;
}
public groovy.text.Template readTemplate(File file) {
String rawTemplate = file.getText('UTF-8')
return new groovy.text.SimpleTemplateEngine().createTemplate(rawTemplate);
}
public void writeTemplate(Template template, def templateBinding, File outputFile) {
logger.lifecycle("Writing templated file ${outputFile}")
def templatedResult = template.make(templateBinding).toString()
outputFile << templatedResult;
}
public Set<File> matchFiles(File directory, String matcher, boolean recursive){
Set<File> matchingFiles = new TreeSet<String>();
Closure match = {
if(it.name.matches(matcher)) {
matchingFiles.add(it);
}
}
if(recursive) {
directory.eachFileRecurse(FileType.FILES, match);
}
else {
directory.eachFile(FileType.FILES,match);
}
return matchingFiles;
}
public void scorchDirectory(File directory) {
deleteDirectory(directory);
createDirectory(directory);
}
public void scrubDirectory(File directory, String pattern){
directory.eachFile(FileType.FILES) {
if(it.name.matches(pattern)){
deleteFile(it);
}
}
}
public void createDirectory(File f){
if(!f.exists()) {
logger.lifecycle("Creating ${f}")
f.mkdirs();
}
}
public void createFile(File f){
if(!f.exists()) {
logger.lifecycle("Creating ${f}")
f.createNewFile();
}
}
public void copyFile(File original, File newFile) {
logger.lifecycle("Copying ${original} to ${newFile}.")
newFile.bytes = original.bytes
}
public void deleteDirectory(File f){
if(f.exists()) {
logger.lifecycle("Deleting ${f}")
f.deleteDir();
}
}
public void deleteFile(File f){
if(f.exists()) {
logger.lifecycle("Deleting ${f}")
f.delete();
}
}
public void generateCucumberTestSuites(Template cucumberTemplate, Template featureTemplate, Set<File> featureFiles, File testSuiteFolder, String
testSuitePackage, String[] glue, File outputFeatureFolder, String pattern) {
scrubDirectory(testSuiteFolder, pattern);
scorchDirectory(outputFeatureFolder);
int count = 0;
for(File featureFile : featureFiles) {
File featureDirectory = new File(outputFeatureFolder, "feature${count}")
createDirectory(featureDirectory);
File newFeatureFile = new File(featureDirectory, featureFile.getName())
def featureTemplateBinding = [
"GENERATED_DATE":new Date().toString(),
"FEATURE_FILE_CONTENT":featureFile.getText("UTF-8")
]
writeTemplate(featureTemplate, featureTemplateBinding, newFeatureFile);
String generatedDate = new Date().toString();
String packageName = testSuitePackage;
String featureDirectoryString = featureDirectory.getCanonicalPath().replace("\\", "/")
String testSuiteName = "CucumberTestSuite${count}"
String joinedGlue = glue.collect{"\""+it+"\""}.join(",");
def cucumberTemplateBinding = [
"GENERATED_DATE":generatedDate,
"PACKAGE_NAME":packageName,
"FEATURE_DIRECTORY":featureDirectoryString,
"TEST_SUITE_NAME":testSuiteName,
"GLUE":joinedGlue
]
String testSuiteFileName = "${testSuiteName}.java";
if(!testSuiteFileName.matches(pattern)) {
throw new Exception("Generated file name ${testSuiteFileName} does not match regex ${pattern}");
}
writeTemplate(cucumberTemplate, cucumberTemplateBinding, new File(testSuiteFolder, testSuiteFileName))
count++;
}
}
task uberJar(type: Jar,dependsOn:[':compileJava',':compileGroovy']) {
zip64 true
from files(sourceSets.main.output.classesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
with jar
manifest {
attributes 'Main-Class': mainClassName
}
}
gradle.startParameter.continueOnFailure = true