I have a project with the following directory structure:
src/main/java
src/main/resources
src/test/java
src/test/resources
I want to add a new folder, integrationTest:
src/integrationTest/java
src/integrationTest/resources
Where I want to keep integration tests totally separate from unit tests. How should I go about adding this? In the build.gradle, I'm not sure how to specify a new task that'd pick this folder build it and run the tests separately.
Gradle has a concept of source sets which is exactly what you need here. You have a detailed documentation about that in the Java Plugin documenation here : https://docs.gradle.org/current/userguide/building_java_projects.html#sec:java_source_sets
You can define a new source set "integrationTest" in your build.gradle
sourceSets {
integrationTest {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/java')
}
resources.srcDir file('src/integration-test/resources')
}
}
This will automatically create new configurations integrationTestCompile and integrationTestRuntime, that you can use to define an new Task integrationTests:
task integrationTest(type: Test) {
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
}
For reference : a working full example can be found here : https://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-integration-testing/
Please add the newly created source folder also to source sets in build.gradle as below:
sourceSets {
main {
java {
srcDirs = ['src']
}
}
test {
java {
srcDirs = ['test']
}
}
integrationTest {
java {
srcDirs = ['integrationTest']
}
}
}
Cheers !
Related
I am using the below configuration build.gradle
plugins {
id "com.google.protobuf" version "0.8.17"
id "java"
}
group "de.prerna.aws.tests"
version "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
ext {
protobufVersion = "3.18.1"
}
dependencies {
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
sourceSets {
main {
proto {
srcDir 'src/main/proto'
}
java {
// include self written and generated code
srcDirs 'src/main/java'
}
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:4.0.0-rc-2'
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.39.0"
}
}
generateProtoTasks.generatedFilesBaseDir = 'generated-sources'
generateProtoTasks {
all().each { task ->
task.plugins { grpc{} }
}
ofSourceSet('main')
}
}
Error
* What went wrong:
Execution failed for task ':processResources'.
> Entry Person.proto is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.2/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details.
A variant of BParolini for build.gradle (Groovy DSL)
tasks.withType(Copy) {
filesMatching("**/*.proto") {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
}
I could fix this problem by adding the following code to my build.gradle.kts:
tasks {
withType<Copy> {
filesMatching("**/*.proto") {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
}
}
Extra info: I'm using Gradle 7.3-rc-3 and Java 17.
Unfortunately nobody explains reasons for this problem, so here is some of my explorations and guesses. Please correct me if you know more.
If found that following build script code causes this error:
proto { srcDir 'src/main/proto' }
If look inside "build/extracted-include-protos" directory, there are original .proto files copied into "build/extracted-include-protos/test" (but not into main).
My guess is that those auto-copied .proto files are originally uses as the only sources, but when adding "src/main/proto" source set we give some compiler tool second set of same files.
Removing this srcDir is not a good idea, because it required for IDEA to correctly open included .proto on Ctrl+click (otherwise it is opened extracted copies which is useless).
I have a cucumber test :
#RunWith(CucumberWithSerenity.class)
#UsePersistantStepLibraries
#CucumberOptions(
features = "src/integrationTest/resources/features/",
glue = {"com/myorg/proj/integrationtest/stepdefinitions"},
plugin = {"pretty", "summary"}
)
public class integrationTestRunner extends ParentClassWithAllMethods {
}
This is test is not defined inside the test folder , but as a seprate folder (as source set, and some one else had created this structure).
The gradle configuration for the sourceset (where the test is ) is as below:
sourceSets {
integrationTest {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/integrationTest/java')
}
resources.srcDir file('src/integrationTest/resources')
}
}
// Dependencies for integrationTest
dependencies {
integrationTestCompileOnly 'org.projectlombok:lombok:1.18.12'
integrationTestAnnotationProcessor 'org.projectlombok:lombok:1.18.12'
integrationTestCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.4.2'
integrationTestImplementation 'net.serenity-bdd:serenity-core:2.2.13'
integrationTestImplementation 'net.serenity-bdd:serenity-cucumber5:2.2.5'
integrationTestImplementation 'net.serenity-bdd:serenity-rest-assured:2.2.13'
integrationTestImplementation 'org.assertj:assertj-core:3.8.0'
integrationTestImplementation 'org.slf4j:slf4j-simple:1.7.7'
}
task integrationTest(type: Test) {
doFirst {
systemProperty 'param1',
System.getProperty('param1')
param1 = System.getProperty('param1')
if (param1 == null)
throw new GradleException("Parameter not passed ./gradlew -DParam<VALUE> ")
}
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
outputs.upToDateWhen { false }
finalizedBy aggregate
}
Looking at the gradle file, there 3 things going on ,
There is a source set defined as integrationTest
The compileCLassPath , runTimeClassPath, srcDir has been defined for the same
Even the resources.srcDir is also being set (where I have application ymls)
I have create application.yml, application-integrationTest.yml inside the resources folder, but still unable to read any proporties using #Value.
Ex:
public class ParentClassWithAllMethods {
#Value("${custom.parameter}")
private String customParameter;
public ResponseOptions<Response> getMethod() {
String debugVal = customParameter;
}
.....
}
When , running the test, I was expecting to get the value defined in my yml file, but its null.
YML file looks like this,
custom:
parameter: https://something.com
Why am I not able to read the application configuration? It's always null !!
Your test class is not starting Spring, that is why you get null. Have a look here https://www.baeldung.com/cucumber-spring-integration, it shows how to connect Spring and Cucumber in JUnit tests.
The test class would then have annotations for Spring and Cucumber like this:
#CucumberContextConfiguration
#SpringBootTest
public class SpringIntegrationTest {
// executeGet implementation
}
I am currently working on a Vaadin 8 project using the gradle vaadin-plugin.
In the project there are 3 SourceSets main,a and b. The later two exclude some views and features. Is it possible to build 3 Artifcats via gradle one for each sourceSet. I tried modifying the war task but that broke the views.
conf{
aCompile.extendsFrom compile
aRuntime.extendsFrom runtime
bCompile.extendsFrom compile
bRuntime.extendsFrom runtime
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', 'src/main/generated']
}
}
a{
java {
srcDirs = ['src/main/java', 'src/main/generated']
exclude 'com/exmaple/features/b'
exclude 'com/exmaple/views/b'
}
compileClasspath += main.output
runtimeClasspath += main.output
output.resourcesDir = 'build/resources/main'
output.classesDir = 'build/classes/java/main'
}
b{
java {
srcDirs = ['src/main/java', 'src/main/generated']
exclude 'com/exmaple/features/a'
exclude 'com/exmaple/views/a'
}
compileClasspath += main.output
runtimeClasspath += main.output
output.resourcesDir = 'build/resources/main'
output.classesDir = 'build/classes/java/main'
}
}
task aWar(type: War) {
appendix = "a"
from sourceSets.a.output
}
task bWar(type: War) {
appendix = "b"
from sourceSets.b.output
}
From https://docs.gradle.org/current/userguide/artifact_management.html#sec:declaring_artifacts you should be able to declare an artifact for every source set.
In your case it would look something like this:
task aWar(type: War, dependsOn: classes) {
baseName = 'a.war'
classpath = project.configurations.aRuntime
}
task bWar(type: War, dependsOn: classes) {
baseName = 'b.war'
classpath = project.configurations.bRuntime
}
artifacts {
archives aWar, bWar
}
The WAR task also allows you to include/exclude classes using a regexp. Checkout more at https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.War.html
My gradle pitest is not able to give me the right results. It looks like it is not able to locate my test files.
I have the following build.gradle file:
apply plugin: "java" apply plugin: "maven" apply plugin: "info.solidsoft.pitest"
group = "myorg" version = 1.0
repositories {
mavenCentral() }
sourceSets.all { set ->
def jarTask = task("${set.name}Jar", type: Jar) {
baseName = baseName + "-$set.name"
from set.output
}
artifacts {
archives jarTask
} }
sourceSets {
api
impl main{ java { srcDir 'src/api/java' srcDir 'src/impl/java' } } test { java { srcDir 'src/test/java' } } }
buildscript {
repositories {
mavenCentral()
//Needed only for SNAPSHOT versions
//maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
}
dependencies {
classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.1.6'
} }
dependencies {
apiCompile 'commons-codec:commons-codec:1.5'
implCompile sourceSets.api.output
implCompile 'commons-lang:commons-lang:2.6'
testCompile 'junit:junit:4.9'
testCompile sourceSets.api.output
testCompile sourceSets.impl.output
runtime configurations.apiRuntime
runtime configurations.implRuntime }
jar {
from sourceSets.api.output
from sourceSets.impl.output }
pitest { println sourceSets.main
targetClasses = ['doubler.*'] targetTests = ['doubler.*'] verbose="on" }
THe output is stored in the correct folder. And when I run gradle test, it also runs fine.
Some additional information about this issue was supplied in the pitest user group.
https://groups.google.com/forum/#!topic/pitusers/8C7BHh-Vb6Y
The tests being run look like this.
#Test
public void testIt2() {
assert new DoublerImpl().testIt(1) == 2;
}
Pitest is correctly reporting that these tests provide 0% coverage of the class. There is no coverage because the assert keyword has been used.
Unless the -ea flag is set in the JVM running the tests assertions are disabled. There is basically hidden if block around this code generated by the compiler
#Test
public void testIt2() {
if (assertionsEnabled) {
assert new DoublerImpl().testIt(1) == 2;
}
}
As assertions are not enabled no code is executed.
To fix the issue use the built in JUnit assertions instead.
http://junit.sourceforge.net/javadoc/org/junit/Assert.html
I have a project with the java plugin applied, and an additionnal source set
project(':dependencie') {
apply plugin: 'java'
sourceSets {
generated {
java {
srcDir 'src/generated/java'
}
}
main {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
test {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
}
}
And another depending of this one :
project(':dependsFrom') {
apply plugin: 'java'
dependencies {
compile(
project(':dependencie')
) { transitive = false }
}
}
My problemes is that when I am trying to compile dependsFrom, it doesn't find the classes of the sourceSet generated for the project dependencie. My workaround is to add the line
output.dir(generated.output, builtBy: 'regenerateFromWsdl')
to the main source set of dependencie but any insight to how "registering" the output of the generated source set for future dependencies would be really helpful.
I you want to model the generated code as a separate source set, you have to create a Jar and publish it via the runtime configuration:
task generatedJar(type: Jar) {
from sourceSets.generated.output
}
artifacts {
runtime generatedJar
}
Alternatively, you could add src/generated/java as another source directory for the main source set, in which case it will get compiled/packaged/exported together with that.
In fact I found a solution. You just need to add the generated sourceSet output to the jar task of dependencie project, as it is this same jar task which "inject" the project into the dependecie system.
My problem was that I tought that any additional sourceSet of the project would have been automatically used by all the tasks of the project.
Here the modified gradle script
project(':dependencie') {
apply plugin: 'java'
sourceSets {
generated {
java {
srcDir 'src/generated/java'
}
}
main {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
test {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
}
jar {
from sourceSets.generated.output
}
}