Making inProgress not generate a single test method instead of the whole test class

fixes gh-1260
This commit is contained in:
Marcin Grzejszczak
2019-11-08 12:51:22 +01:00
parent 588b05af1f
commit cf44bdd73b
6 changed files with 188 additions and 7 deletions

3
.gitignore vendored
View File

@@ -42,4 +42,5 @@ interpolated-settings.xml
interpolated-pom.xml
dependency-reduced-pom.xml
.vscode/
.vscode/
.flattened-pom.xml

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class InProgressContractMethodPreProcessor implements MethodPreProcessor {
@Override
public boolean shouldContinue() {
return false;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
return metadata.isInProgress();
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
interface MethodPreProcessor extends MethodVisitor<MethodPreProcessor> {
@Override
default MethodVisitor<MethodPreProcessor> apply(
SingleContractMetadata singleContractMetadata) {
return this;
}
/**
* @return {@code true} if method should be processed
*/
default boolean shouldContinue() {
return true;
}
}

View File

@@ -22,6 +22,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
/**
@@ -33,10 +36,14 @@ import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
*/
class SingleMethodBuilder {
private static final Log log = LogFactory.getLog(SingleMethodBuilder.class);
private List<MethodAnnotations> methodAnnotations = new LinkedList<>();
private List<MethodMetadata> methodMetadata = new LinkedList<>();
private List<MethodPreProcessor> methodPreProcessors = new LinkedList<>();
private List<MethodPostProcessor> methodPostProcessors = new LinkedList<>();
private List<Given> givens = new LinkedList<>();
@@ -86,6 +93,7 @@ class SingleMethodBuilder {
SingleMethodBuilder restAssured() {
return given(
new JavaRestAssuredGiven(this.blockBuilder, this.generatedClassMetaData))
.methodPreProcessor(new InProgressContractMethodPreProcessor())
.given(new SpockRestAssuredGiven(this.blockBuilder,
this.generatedClassMetaData))
.when(new JavaRestAssuredWhen(this.blockBuilder,
@@ -101,7 +109,8 @@ class SingleMethodBuilder {
}
SingleMethodBuilder jaxRs() {
return given(new JaxRsGiven(this.generatedClassMetaData))
return methodPreProcessor(new InProgressContractMethodPreProcessor())
.given(new JaxRsGiven(this.generatedClassMetaData))
.when(new JavaJaxRsWhen(this.blockBuilder, this.generatedClassMetaData))
.when(new SpockJaxRsWhen(this.blockBuilder, this.generatedClassMetaData))
.then(new JavaJaxRsThen(this.blockBuilder, this.generatedClassMetaData))
@@ -112,7 +121,8 @@ class SingleMethodBuilder {
SingleMethodBuilder messaging() {
// @formatter:off
return given(new JavaMessagingGiven(this.blockBuilder, this.generatedClassMetaData))
return methodPreProcessor(new InProgressContractMethodPreProcessor())
.given(new JavaMessagingGiven(this.blockBuilder, this.generatedClassMetaData))
.given(new SpockMessagingGiven(this.blockBuilder, this.generatedClassMetaData))
.when(new MessagingWhen(this.blockBuilder, this.generatedClassMetaData))
.then(new JavaMessagingWithBodyThen(this.blockBuilder,
@@ -140,6 +150,11 @@ class SingleMethodBuilder {
return this;
}
SingleMethodBuilder methodPreProcessor(MethodPreProcessor methodPreProcessor) {
this.methodPreProcessors.add(methodPreProcessor);
return this;
}
SingleMethodBuilder methodPostProcessor(MethodPostProcessor methodPostProcessor) {
this.methodPostProcessors.add(methodPostProcessor);
return this;
@@ -154,6 +169,14 @@ class SingleMethodBuilder {
// \n
this.blockBuilder.addEmptyLine();
this.generatedClassMetaData.toSingleContractMetadata().forEach(metaData -> {
boolean stopProcessing = shouldStopProcessing(metaData);
if (stopProcessing) {
if (log.isDebugEnabled()) {
log.debug("The method for meta data [" + metaData
+ "] will not be processed further. At least one method pre-processor declared that this method should be skipped.");
}
return;
}
// @Test
if (visit(this.methodAnnotations, metaData, false)) {
this.blockBuilder.addEmptyLine();
@@ -187,6 +210,14 @@ class SingleMethodBuilder {
return this.blockBuilder;
}
private boolean shouldStopProcessing(SingleContractMetadata metaData) {
List<MethodPreProcessor> matchingPreProcessors = this.methodPreProcessors.stream()
.filter(m -> m.accept(metaData))
.collect(Collectors.toCollection(LinkedList::new));
matchingPreProcessors.forEach(m -> m.apply(metaData));
return matchingPreProcessors.stream().anyMatch(m -> !m.shouldContinue());
}
private MethodMetadata pickMetadatum() {
return this.methodMetadata.stream().filter(Acceptor::accept).findFirst()
.orElseThrow(() -> new IllegalStateException(

View File

@@ -181,6 +181,10 @@ class SingleContractMetadata {
return this.http
}
boolean isInProgress() {
return this.contract.isInProgress()
}
boolean isMessaging() {
return !isHttp()
}

View File

@@ -219,6 +219,10 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock
}
private String singleTestGenerator(Contract contractDsl) {
return singleTestGenerator([contractDsl])
}
private String singleTestGenerator(Collection<Contract> contractDsls) {
return new JavaTestGenerator() {
@Override
ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) {
@@ -235,15 +239,15 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock
}
})
}
}.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData)
}.buildClass(properties, [contractMetadata(contractDsls)], "foo", generatedClassData)
}
private GeneratedClassMetaData generatedClassMetaData(Contract contractDsl) {
new GeneratedClassMetaData(properties, [contractMetadata(contractDsl)], "foo", generatedClassData)
new GeneratedClassMetaData(properties, [contractMetadata([contractDsl])], "foo", generatedClassData)
}
ContractMetadata contractMetadata(Contract contractDsl) {
return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl)
ContractMetadata contractMetadata(Collection<Contract> contractDsls) {
return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsls)
}
@Issue('#187')
@@ -3054,4 +3058,76 @@ DocumentContext parsedJson = JsonPath.parse(json);
}
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
@Issue('#1260')
def 'should generate test methods for not in progress contracts [#methodBuilderName]'() {
given:
List<Contract> contractDsl = [
Contract.make {
name("httpContractNotInProgress")
request {
method PUT()
url '/httpContractNotInProgress'
}
response {
status OK()
}
},
Contract.make {
name("httpContractInProgress")
inProgress()
request {
method PUT()
url '/httpContractInProgress'
}
response {
status OK()
}
},
Contract.make {
name("messagingContractNotInProgress")
input {
triggeredBy("toString()")
}
outputMessage {
sentTo("messagingContractNotInProgress")
body([type: "messagingContractNotInProgress"])
}
},
Contract.make {
name("messagingContractInProgress")
inProgress()
input {
triggeredBy("toString()")
}
outputMessage {
sentTo("messagingContractNotInProgress")
body([type: "messagingContractNotInProgress"])
}
}
]
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
SyntaxChecker.tryToCompile(methodBuilderName, test)
and:
test.contains('''httpContractNotInProgress''')
test.contains('''messagingContractNotInProgress''')
and:
!test.contains('''httpContractInProgress''')
!test.contains('''messagingContractInProgress''')
where:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"testng" | { properties.testFramework = TestFramework.TESTNG }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"jaxrs-spock" | {
properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT
}
"jaxrs" | {
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
}
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
}