Cucumber-jvm runner with many features, just run one - cucumber

I have this project structure:
/src
/it
/java
/com/xxx/test/it
ContextSteps
/inventory
InventoryIT
InventorySteps
/resources
/com/xxx/test/it/inventory
1.feature
2.feature
Runner InventoryIT (both features are annotated with #inventory)
#RunWith(Cucumber.class)
#CucumberOptions(tags = "#inventory")
public class InventoryIT {
}
Note that ContextSteps in injected in InventorySteps through cucumber-picocontainer.
When I execute project tests through this runner (with maven or from the IDE as well), I expect both 1.feature and 2.feature run (because both are placed in the same resources package), but just runs the first one: 1.feature.
Am I missing something?
Thanks for the help.

Still wondering why is just running one of the two features... can be fixed setting manually the features resources path:
features = "src/it/resources/com/xxx/test/it/inventory")
through #CucumberOptions annotation in the InventoryIT runner.
#RunWith(Cucumber.class)
#CucumberOptions(tags = "#inventory", features = "src/it/resources/com/xxx/test/it/inventory")
public class InventoryIT {
}
Making this change, both feature run.

Related

Is additional context configuration required when upgrading cucumber-jvm from version 4 to version 6?

I am using cucumber-jvm to perform some functional tests in Kotlin.
I have the standard empty runner class:
#RunWith(Cucumber::class)
#CucumberOptions(features=[foo],
glue=[bar],
plugin=[baz],
strict=true,
monochrome=true)
class Whatever
The actual steps are defined in another class with the #ContextConfiguration springframework annotation.
This class also uses other spring features like #Autowire or #Qualifier
#ContextConfiguration(locations=["x/y/z/config.xml"])
class MyClass {
...
#Before
...
#Given("some feature file stuff")
...
// etc
}
This all work fine in cucumber version 4.2.0, however upgrading to version 6.3.0 breaks things. After updating the imports to match the new cucumber project layout the tests now fail with this error:
io.cucumber.core.backend.CucumberBackendException: Please annotate a glue class with some context configuration.
It provides examples of what it means...
For example:
#CucumberContextConfiguration
#SpringBootTest(classes = TestConfig.class)
public class CucumberSpringConfiguration {}
Or:
#CucumberContextConfiguration
#ContextConfiguration( ... )
public class CucumberSpringConfiguration {}
It looks like it's telling me I can just add #CucumberContextConfiguration to MyClass.
But why?
I get the point of #CucumberContextConfiguration, it's explained well here but why do I need it now with version 6 when version 4 got on fine without it? I can't see any feature that was deprecated and replaced by this.
Any help would be appreciated :)
Since the error matches exactly with the error I was getting in running Cucumber tests with Spring Boot, so I am sharing my fix.
One of the probable reason is: Cucumber can't find the CucumberSpringConfiguration
class in the glue path.
Solution 1:
Move the CucumberSpringConfiguration class inside the glue path (which in my case was inside the steps package).
Solution 2:
Add the CucumberSpringConfiguration package path in the glue path.
The below screenshot depicts my project structure.
As you can see that my CucumberSpringConfig class was under configurations package so it was throwing me the error when I tried to run feature file from command prompt (mvn clean test):
"Please annotate a glue class with some context configuration."
So I applied solution 2, i.e added the configurations package in the glue path in my runner class annotation.
And this is the screenshot of the contents of CucumberSpringConfiguration class:
Just an extra info:
To run tests from command prompt we need to include the below plugin in pom.xml
https://github.com/cucumber/cucumber-jvm/pull/1959 removed the context configuration auto-discovery. The author concluded that it hid user errors and removing it would provide more clarity and reduce complexity. It also listed the scenarios where the context configuration auto-discovery used to apply.
Note that it was introduced after https://github.com/cucumber/cucumber-jvm/pull/1911, which you had mentioned.
Had the same error but while running Cucumber tests from Jar with Gradle.
The solution was to add a rule to the jar task to merge all the files with the name "META-INF/services/io.cucumber.core.backend.BackendProviderService" (there could be multiple of them in different Cucumber libs - cucumber-java, cucumber-spring).
For Gradle it is:
shadowJar {
....
transform(AppendingTransformer) {
resource = 'META-INF/services/io.cucumber.core.backend.BackendProviderService'
}
}
For Maven something like this:
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/io.cucumber.core.backend.BackendProviderService</resource>
</transformer>
</transformers>
A bit more explanation could be found in this answer

Gradle ant build file not not available during configuration phase

I can't figure out how to execute ant target in case that ant build.xml file is not available during configuration phase. Because it's a remote resource (Maven Remote Resources Plugin).
So basically first I need to get this remote resource like this:
configurations {
remoteResources
}
dependencies.remoteResources 'group:my-remote-resource:version'
task getRemoteResources(type: Copy) {
from(zipTree(configurations.remoteResources.first()))
into("$buildDir/remote-resources")
// replace placeholders
filter(org.apache.tools.ant.filters.ReplaceTokens, , tokens: remotePlaceholders)
}
Only then I have build.xml in
"$buildDir/remote-resources"
But I can't use ant.importBuild as that expects build.xml to be available during the configuration, which is not my case.
I was thinking to move the remote resource "download" into initialization phase, but I have a multi-module project and although only some sub-projects are using this remote resource they all has it own placeholders to replace.
Is there any way how to execute ant targets in this special case?
EDIT: I found pretty nice solution utilising Ant's ProjectHelper and Project classes. So I guess that is my answer..
So here is the final solution. (as already mentioned credits go to groovy-almanac)
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
task executeAntTarget(dependsOn: getRemoteResources) << {
def antFile = new File("$buildDir/remote-resources/build.xml")
def antProject = new Project()
antProject.init()
ProjectHelper.projectHelper.parse(antProject, antFile)
antProject.executeTarget('<target-to-execute>');
}

Unit testing in android studio

I am using newest version of android studio gradle plugin 1.2.3. I am unable to understand how to create unit tests in it; all the available answers are for older version of android. Help me.
first of all you need a different folder structure for your unit tests.
android studio automatically generats the androidTest folder for instrumentation tests, but you can't put your unit tests in there. so you have to create a "test" folder:
- src
-- androidTest //for instrumentation tests
-- main //source code
-- test //for unit tests
use the same package structure for your tests as for the class you want to test.
you can switch in your build variants of android studio between Android Instrumentation Tests and Unit Tests.
depending on your selection test or androidTest folder will be show in your project tab.
finally you have to add junit to your dependencies in gradle:
dependencies {
testCompile 'junit:junit:4.12'
}
the test classes in your test folder can for example look like this:
package package.of.class.to.test
import org.junit.Before;
import org.junit.Test;
...
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class TestSomething{
#Before
public void setup(){
// test setup
}
#Test
public void testSomething(){
// your unit tests like these simple examples
assertThat(anyBooleanResult, is(expectedBooleanResult));
assertEquals(anyIntResult, expectedIntResult);
}
}
for further information you can also take a look on this thread.

Gradle Incremental Tasks: Adding already generated code to the classpath

I have created a custom Gradle task that generates some java code. To optimize execution this plugin uses the #InputDirectory and #OutputDirectory annotations, so that the code does not have to be generated each build.
However, I do want this task to add the generated code to the classpath. I am currently doing this by
class JaxbTask extends DefaultTask {
#OutputDirectory
File destdir = project.file( "${project.buildDir}/generated-sources/mygen" )
#InputDirectory
File schemaRoot = project.file("${project.projectDir}/src/main/resources/myschema/")
#TaskAction
def main() {
..
project.sourceSets.main.java.srcDirs += destdir
..
}
The problem is that the TaskAction is not executed and the sourcedirectory is not added to the compile path when the generated code is up to date. Is there any way to make sure that the modification of the sourcepath is always performed?
A task should never try to configure the build model. Configuration is the responsibility of build scripts and plugins, and needs to happen in the configuration phase (before any task has run).

Is it possible to use classes compiled by Gradle buildSrc in main Groovy project?

Classes compiled by buildSrc/build.gradle are not resolved at runtime when they are used in main PROJECT classes.
My Groovy project structure looks like this:
-PROJECT
-buildSrc/
-build.gradle
-/src/main/groovy
- com.company.global.test.report
-src/test/groovy
-build.gradle
Is there something I can add to the top-level PROJECT/build.gradle to allow the classes compiled by it to use the classes compiled by buildSrc/build.gradle?
buildSrc is its own build (not project) that gets executed before the main build. Its sole purpose is to make some classes (plugins, tasks, regular classes) available to the build scripts of the main build. Hence you could call it a "meta-build".
Technically, it would be possible to add the compiled classes of buildSrc to the compile or runtime class path of a project in the main build, but I don't recommend to do it. There is very likely a better way to achieve your goals (but I don't know what those are).
Here is how to do it with Gradle 2.12:
In your_project/buildSrc/build.gradle
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
// Thanks to this, IDE like IntelliJ will provide you with "Navigate to sources"
artifacts {
archives sourcesJar
}
In your_project/build.gradle
ext.buildSrcJars = fileTree("$rootDir/buildSrc/build/libs") { include("*.jar") exclude("*sources.jar")}
// Works in every subproject
dependencies {
compile buildSrcJars
}

Resources