Spock basic generation strategy

This commit is contained in:
Jakub Kubrynski
2015-01-23 00:21:22 +01:00
parent 7a68e8d7b7
commit 94c86af499
11 changed files with 175 additions and 59 deletions

12
pom.xml
View File

@@ -31,6 +31,18 @@
<version>2.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>0.7-groovy-2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.53</version>
</dependency>
</dependencies>

View File

@@ -1,6 +1,7 @@
package eu.coderate.accurest
import eu.coderate.accurest.builder.ClassBuilder
import eu.coderate.accurest.builder.Lang
import eu.coderate.accurest.util.NamesUtil
import static eu.coderate.accurest.builder.ClassBuilder.createClass
@@ -15,12 +16,18 @@ class TestGenerator {
private final String basePackageForTests
private final String baseClassForTests
private final String ruleClassForTests
private final Lang lang
TestGenerator(String mocksBaseDirectory, String basePackageForTests, String baseClassForTests, String ruleClassForTests) {
TestGenerator(String mocksBaseDirectory, String basePackageForTests, String baseClassForTests, String ruleClassForTests, Lang lang) {
this.mocksBaseDirectory = getClass().getClassLoader().getResource(mocksBaseDirectory).path
this.basePackageForTests = basePackageForTests
this.baseClassForTests = baseClassForTests
if (lang == Lang.GROOVY && !baseClassForTests) {
this.baseClassForTests = 'spock.lang.Specification'
} else {
this.baseClassForTests = baseClassForTests
}
this.ruleClassForTests = ruleClassForTests
this.lang = lang
}
public String generate() {
@@ -42,20 +49,26 @@ class TestGenerator {
}
private String addClass(File directory) {
ClassBuilder clazz = createClass(NamesUtil.capitalize(NamesUtil.afterLast(directory.path, '/')), basePackageForTests, baseClassForTests)
.addImport('org.junit.Test')
.addImport('org.junit.Rule')
.addStaticImport('org.hamcrest.Matchers.*')
ClassBuilder clazz = createClass(NamesUtil.capitalize(NamesUtil.afterLast(directory.path, '/')), basePackageForTests, baseClassForTests, lang)
.addStaticImport('com.jayway.restassured.RestAssured.*')
.addStaticImport('com.jayway.restassured.matcher.RestAssuredMatchers.*')
.addRule('com.test.MyRule')
.addImport('java.util.regex.Pattern')
if (lang == Lang.JAVA) {
clazz.addImport('org.junit.Test')
}
if (ruleClassForTests) {
clazz.addImport('org.junit.Rule')
.addRule(ruleClassForTests)
}
directory.listFiles().each {
clazz.addMethod(createTestMethod(it))
clazz.addMethod(createTestMethod(it, lang))
}
return clazz.build()
}
public static void main(String[] args) {
print new TestGenerator("", 'io.test', 'com.test.BaseClass', "").generate()
print new TestGenerator('stubs', 'io.test', '', '', Lang.GROOVY).generate()
}
}

View File

@@ -14,22 +14,33 @@ class ClassBuilder {
private final List<String> staticImports = []
private final List<String> rules = []
private final List<MethodBuilder> methods = []
private final String modifier
private final String suffix
private ClassBuilder(String className, String packageName, String baseClass) {
private ClassBuilder(String className, String packageName, String baseClass, Lang lang) {
if (baseClass) {
imports << baseClass
}
this.baseClass = NamesUtil.afterLastDot(baseClass)
this.packageName = packageName
this.className = className
switch (lang) {
case Lang.JAVA:
modifier = "public "
suffix = ";"
break
case Lang.GROOVY:
modifier = ""
suffix = ""
}
}
static ClassBuilder createClass(String className, String packageName) {
return createClass(className, packageName, null)
static ClassBuilder createClass(String className, String packageName, Lang lang) {
return createClass(className, packageName, null, lang)
}
static ClassBuilder createClass(String className, String packageName, String baseClass) {
return new ClassBuilder(className, packageName, baseClass)
static ClassBuilder createClass(String className, String packageName, String baseClass, Lang lang) {
return new ClassBuilder(className, packageName, baseClass, lang)
}
ClassBuilder addImport(String importToAdd) {
@@ -54,21 +65,25 @@ class ClassBuilder {
}
String build() {
BlockBuilder clazz = new BlockBuilder(" ")
.addLine("package $packageName;")
BlockBuilder clazz = new BlockBuilder("\t")
.addLine("package $packageName" + suffix)
.addEmptyLine()
imports.sort().each {
clazz.addLine("import $it;")
clazz.addLine("import $it" + suffix)
}
if (!imports.empty) {
clazz.addEmptyLine()
}
clazz.addEmptyLine()
staticImports.sort().each {
clazz.addLine("static import $it;")
clazz.addLine("import static $it" + suffix)
}
if (!staticImports.empty) {
clazz.addEmptyLine()
}
clazz.addEmptyLine()
def classLine = "public class $className"
def classLine = modifier + "class $className"
if (baseClass) {
classLine += " extends $baseClass"
}
@@ -78,10 +93,12 @@ class ClassBuilder {
clazz.startBlock()
rules.sort().each {
clazz.addLine("@Rule")
clazz.addLine("public " + it + " " + NamesUtil.uncapitalize(it) + " = new $it();")
clazz.addLine("public " + it + " " + NamesUtil.uncapitalize(it) + " = new $it()" + suffix)
}
clazz.endBlock()
clazz.addEmptyLine()
if (!rules.empty) {
clazz.addEmptyLine()
}
methods.each {
clazz.addBlock(it)

View File

@@ -0,0 +1,18 @@
package eu.coderate.accurest.builder
/**
* @author Jakub Kubrynski
*/
class JavaMethodBodyBuilder {
/*
given()
.contentType("application/json")
.header("Accept", "application/json")
.body("{'name': 'MyApp', 'description' : 'awesome app'}".replaceAll("'", "\"")).
expect()
.statusCode(200).body("id", is(not(nullValue()))).
when()
.post(root.toString() + "rest/applications").asString();*/
}

View File

@@ -0,0 +1,10 @@
package eu.coderate.accurest.builder
/**
* @author Jakub Kubrynski
*/
enum Lang {
JAVA, GROOVY
}

View File

@@ -1,19 +0,0 @@
package eu.coderate.accurest.builder
/**
* @author Jakub Kubrynski
*/
class MethodBodyBuilder {
private final Map stubDefinition
MethodBodyBuilder(Map stubDefinition) {
this.stubDefinition = stubDefinition
}
void appendTo(BlockBuilder blockBuilder) {
blockBuilder.startBlock()
blockBuilder.addLine("//" + stubDefinition.request.method)
blockBuilder.addLine("//" + stubDefinition.response.status)
blockBuilder.endBlock()
}
}

View File

@@ -10,22 +10,30 @@ class MethodBuilder {
private final String methodName
private final Map stubContent
private final Lang lang
private MethodBuilder(String methodName, Map stubContent) {
private MethodBuilder(String methodName, Map stubContent, Lang lang) {
this.stubContent = stubContent
this.methodName = methodName
this.lang = lang
}
static MethodBuilder createTestMethod(File stubsFile) {
static MethodBuilder createTestMethod(File stubsFile, Lang lang) {
Map stubContent = new JsonSlurper().parse(stubsFile)
String methodName = NamesUtil.uncapitalize(NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator)))
return new MethodBuilder(methodName, stubContent)
return new MethodBuilder(methodName, stubContent, lang)
}
void appendTo(BlockBuilder blockBuilder) {
blockBuilder.addLine('@Test')
blockBuilder.addLine("public void $methodName() {")
new MethodBodyBuilder(stubContent).appendTo(blockBuilder)
String modifier
if (lang == Lang.JAVA) {
blockBuilder.addLine('@Test')
modifier = "public void "
} else {
modifier = "def "
}
blockBuilder.addLine(modifier + "$methodName() {")
new SpockMethodBodyBuilder(stubContent).appendTo(blockBuilder)
blockBuilder.addLine('}')
}
}

View File

@@ -0,0 +1,49 @@
package eu.coderate.accurest.builder
import groovy.transform.PackageScope
/**
* @author Jakub Kubrynski
*/
@PackageScope
class SpockMethodBodyBuilder {
private final Map stubDefinition
SpockMethodBodyBuilder(Map stubDefinition) {
this.stubDefinition = stubDefinition
}
void appendTo(BlockBuilder blockBuilder) {
blockBuilder.startBlock()
blockBuilder.addLine('given:').startBlock()
blockBuilder.addLine('def request = given()')
blockBuilder.startBlock().startBlock()
stubDefinition.request.headers.each {
blockBuilder.addLine(".header('$it.key', '$it.value.equalTo')")
}
if (stubDefinition.request.bodyPatterns) {
blockBuilder.addLine('.body(\'' + stubDefinition.request.bodyPatterns[0].matches + '\')')
}
blockBuilder.endBlock().endBlock().endBlock().addEmptyLine()
blockBuilder.addLine('when:').startBlock()
blockBuilder.addLine('def response = given().spec(request)')
blockBuilder.startBlock().startBlock()
blockBuilder.addLine('.' + stubDefinition.request.method.toLowerCase() + '("' + stubDefinition.request.url + '")')
blockBuilder.endBlock().endBlock().endBlock().addEmptyLine()
blockBuilder.addLine('then:').startBlock()
blockBuilder.addLine('response.statusCode == ' + stubDefinition.response.status)
stubDefinition.response.headers.each {
blockBuilder.addLine("response.header('$it.key') == '$it.value'")
}
if (stubDefinition.response.body) {
blockBuilder.addLine("Pattern.compile('$stubDefinition.response.body', Pattern.DOTALL).matcher(response.body.asString()).matches()")
}
blockBuilder.endBlock()
blockBuilder.endBlock()
}
}

View File

@@ -1,7 +1,7 @@
{
"request": {
"method": "GET",
"url": "/some/thing"
"url": "/some"
},
"response": {
"status": 200,

View File

@@ -0,0 +1,17 @@
{
"request": {
"method": "POST",
"url": "/some/thing",
"headers": {
"Accept": {
"equalTo": "text/plain"
}
},
"bodyPatterns" : [ {
"matches" : "{\"client\":\"1234\"}"
} ]
},
"response": {
"status": 400
}
}

View File

@@ -1,9 +0,0 @@
{
"request": {
"method": "POST",
"url": "/some/thing"
},
"response": {
"status": 400
}
}