Spring Profiles in Cucumber Testing and Gradle - java

I have an automation test suite that is using Cucumber and Spring running with a Gradle build. I am facing an issue where depending on environment the property file used will be different. I know there is a way to use Profile annotations to specify ContextConfiguration but I can not find any resources on how to get started on this.
I believe I have to create a ProfileManager Class but I am not sure how to connect this to the #ContectConfiguration annotating my Cucumber Step Definitions and the Property Sources in my Configuration Class.
Here are some of my code samples.
StepDefintions.java
#CucumberContextConfiguration
#ContextConfiguration(classes = {ApplicationConfiguration.class, DynamoDBConfiguration.class})
#TestPropertySource("classpath:application-test-local.properties")
//#TestPropertySource("classpath:application-test.properties")
public class StepDefinition {
#Given("I set stuff up")
public void myGivenStep() {
app.assertTheThings()
#When("I do things")
public void myWhenStep() {
app.checksStuff();
}
.....
}
ApplicationConfiguraton.java
#Configuration
public class ApplicationConfiguration {
#Autowired
private Environment env;
.....
}
build.gradle
{
.....
task cucumber() {
dependsOn assemble, testClasses
doLast {
javaexec {
main='io.cucumber.core.cli.Main'
classpath=configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
def env = System.getProperty('testingENV')
println("Testing in " + env.toUpperCase() + ' Enviornment')
systemProperties = System.properties
def feature = ''
if (project.hasProperty('feature')) {
def arg1 = project.getProperty('feature')
feature = arg1
}
args = [
'--plugin', 'pretty',
'--plugin', 'json:target/cucumber-report.json',
'--glue', 'com.testautomation.cucumber',
"src/test/resources/com/testautomation/cucumber/feature/${feature}"
]
}
}
}
}
Basically I would like to use my testingENV system prop to define the profile and change which property source is being used without having to comment lines out everytime I am switching envs.

Related

How do i initiate Spring #Autowired instances when running a Cucumber test?

I'm able to initiate Spring when i'm debbuging StepDefinitions.java, but running the test from gradle produces null. Do I need an aditional glue?
Produces null: gradle cucumber
Produces null: running myFeature.features
Produces myService (working): running Stepdefinitions.java
I have tried the following code:
#ContextConfiguration(
classes = Application.class,
loader = SpringBootContextLoader.class)
#WebAppConfiguration
Current StepDefinitions:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Application.class)
#WebAppConfiguration
public class StepDefinitions{
private static String roll;
#Autowired
MyService myService;
/** Reset all static values before running test cases */
#BeforeClass
public static void resetValues() {
roll = "";
}
//I use swedish, "Given"
#Givet("Jag har rollen {string}")
public void getRole(String roll) {
assertNotNull(roll);
this.roll = roll;
myService.useRole(roll);
}
}
gradle.build:
dependencies {
compile files('../libs/cucumber-spring-4.7.1.jar')
testCompile 'io.cucumber:cucumber-java:' + cucumberVersion
testCompile 'io.cucumber:cucumber-junit:' + cucumberVersion
...
}
task cucumber() {
dependsOn assemble, compileTestJava
doLast {
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime +
sourceSets.main.output + sourceSets.test.output
args = ['--plugin', 'pretty', '--glue', 'steps/rufs',
'src/test/resources/features', '--tags','#rufs']
}
}
}
You are not getting JUnit involved anywhere when running from Gradle. #RunWith is used by JUnit, and this in turn is what prompts Spring to get involved. When Cucumber is running as your suite, it's ignoring those annotations because it doesn't understand them.
You'll need to use JUnit as your suite (i.e. not run cucumber.api.cli.Main). You then have a problem because you need to use two "runners": Cucumber and Spring.
The way around this is JUnit's "rules" for one of the runners. Spring has a Rule, but as far as I can see Cucumber does not. In this case, use the Cucumber runner:
#RunWith(Cucumber.class)
in combination with Spring's rules, as described here: How to run JUnit SpringJUnit4ClassRunner with Parametrized?

Spring boot Test fails saying, Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean

Test Class:-
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { WebsocketSourceConfiguration.class,
WebSocketSourceIntegrationTests.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
"websocket.path=/some_websocket_path", "websocket.allowedOrigins=*",
"spring.cloud.stream.default-binder=kafka" })
public class WebSocketSourceIntegrationTests {
private String port = "8080";
#Test
public void testWebSocketStreamSource() throws IOException, InterruptedException {
StandardWebSocketClient webSocketClient = new StandardWebSocketClient();
ClientWebSocketContainer clientWebSocketContainer = new ClientWebSocketContainer(webSocketClient,
"ws://localhost:" + port + "/some_websocket_path");
clientWebSocketContainer.start();
WebSocketSession session = clientWebSocketContainer.getSession(null);
session.sendMessage(new TextMessage("foo"));
System.out.println("Done****************************************************");
}
}
I have seen same issue here but nothing helped me. May I know what I'm missing ?
I have spring-boot-starter-tomcat as compile time dependency in the dependency Hierarchy.
This message says:
You need to configure at least 1 ServletWebServerFactory bean in the ApplicationContext, so if you already have spring-boot-starter-tomcat you need to either autoconfigure that bean or to do it manually.
So, in the test there are only 2 configuration classes to load the applicationContext, these are = { WebsocketSourceConfiguration.class, WebSocketSourceIntegrationTests.class }, then at least in one of these classes there should be a #Bean method returning an instance of the desired ServletWebServerFactory.
* SOLUTION *
Make sure to load all the beans within your configuration class
WebsocketSourceConfiguration {
#Bean
ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
}
OR also enable the AutoConfiguration to do a classpath scanning and auto-configuration of those beans.
#EnableAutoConfiguration
WebsocketSourceConfiguration
Can be done also at the Integration Test class.
#EnableAutoConfiguration
WebSocketSourceIntegrationTests
For more information check the SpringBootTest annotation documentation
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html
in 2.0.5.RELEASE i faced a similar issue when I had the following.
package radon;
..
#SpringBootApplication
public class Initializer {
public static void main(String[] args) {
SpringApplication.run(Config.class, args);
}
}
package radon.app.config;
#Configuration
#ComponentScan({ "radon.app" })
public class Config {
..
}
Changing the package of Initializer from radon to radon.app fixed the issue.
this is because spring is not able to load the properties file at runtime, i was using spring profiles and wasn't providing the (program or vm) argument at runtime( java -jar application.jar) , adding vm argument of profile resolved the issue for me.
java -jar -Dspring.profiles.active=dev application.jar
or using program argument
java -jar application.jar --spring.profiles.active=prod --spring.config.location=c:\config
For web applications, extends *SpringBootServletInitializer* in main class.
#SpringBootApplication
public class YourAppliationName extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(YourAppliationName.class, args);
}
}

how to capture Build Info using Gradle and Spring Boot

I am trying to get access to build info values such as version in my Java main application using Spring Boot and Gradle.
I can't find any documentation / examples of how to configure the
build.gradle
application.yml (if required)
Java main class
could someone please help with a small code example for the above files.
In my build.gradle file I will have the version entry, so how to get this into Java main class using Spring Boot and Gradle.
build.gradle
version=0.0.1-SNAPSHOT
I've tried adding
build.gradle
apply plugin: 'org.springframework.boot'
springBoot {
buildInfo()
}
but the buildInfo() isn't recognised as a keyword in Intellij
In my Java main class I have the following:
public class MyExampleApplication implements CommandLineRunner {
#Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(MyExampleApplication.class, args);
}
#Override
public void run(String[] args) throws Exception{
Environment env = (Environment) context.getBean("environment");
displayInfo(env);
}
private static void displayInfo(Environment env) {
log.info("build version is <" + env.getProperty("version")
}
But when I run this - the output from env.getProperty("version") is showing as null.
Spring Boot auto-configures a BuildProperties bean with the information generated by buildInfo().
So to get the information use context.getBean(BuildProperties.class).getVersion();.
I managed to get it working now - using the help pointer that Vampire gave below and some other sources. The key was adding the actuator class to the project dependency.
Note: Intellj doesn't seem to recognise buildInfo() in the springBoot tag - but it does run ok - so don't be put off.
build.gradle
buildscript {
ext {
springBootVersion = '1.5.6.RELEASE'
gradleVersion = '3.3'
}
repositories {
mavenLocal()
maven { url "http://cft-nexus.ldn.xxxxxxxxx.com:8081/nexus/content/groups/public/" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'application'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
springBoot{
buildInfo {
additionalProperties = [
'foo': 'bar'
]
}
}
compile "org.springframework.boot:spring-boot-starter-actuator"
MyExampleApplication
#Slf4j
#EnableIntegration
#EnableLoaderApplication
#SpringBootApplication
#EnableDiscoveryClient
public class MyExampleApplication implements CommandLineRunner {
private static final String SYSTEM_NAME_INFO = "My Example Application";
private static final String VERSION="0.0.1";
#Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(MyExampleApplication.class, args);
}
#Override
public void run(String[] args) throws Exception{
BuildProperties buildProperties = context.getBean(BuildProperties.class);
displayInfo(buildProperties);
}
private static void displayInfo(BuildProperties buildProperties) {
log.info("build version is <" + buildProperties.getVersion() + ">");
log.info("value for custom key 'foo' is <" + buildProperties.get("foo") + ">");
}
}
Screenshot of Console output when running the Application in Intellj
pasting the output as well incase the image doesn't display
> 2017-11-14 14:35:47.330 INFO 22448 --- [ main]
> o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase
> 2147483647 2017-11-14 14:35:47.448 INFO 22448 --- [ main]
> s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s):
> 8780 (http) 2017-11-14 14:35:47.451 INFO 22448 --- [ main]
> c.u.o.metrics.MyExampleApplication : build version is
> <0.0.1-SNAPSHOT> 2017-11-14 14:35:47.451 INFO 22448 --- [
> main] c.u.o.myexample.MyExampleApplication : value for custom key
> 'foo' is <bar>
UPDATE
After reviewing this with my colleague we decided to move the some of the build properties, e.g. version (above) out of the build.gradle file and into gradle.properties file. This gives us a cleaner separation for build details and properties. When you run Gradle build it automatically pulls these values in and they are available in the BuildProperties bean in the Java main class as shown in the example above.
gradle.properties
group=com.xxx.examplesource
version=0.0.1-SNAPSHOT
gradleVersion=3.3
add following to your Gradle script.It inserts the version into the jar manifest correctly, as shown here:
version = '1.0'
jar {
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart',
'Implementation-Version': version
}
}
Your code will be able to pick up the version from that jar manifest file:
public class BuildVersion {
public static String getBuildVersion(){
return BuildVersion.class.getPackage().getImplementationVersion();
}
}
Refer the link below for more details: https://github.com/akhikhl/wuff/wiki/Manifest-attributes-in-build.gradle
Easy way to get version number in Spring boot
#Controller
#RequestMapping("/api")
public class WebController {
private final BuildProperties buildProperties;
public WebController(BuildProperties properties) {
buildProperties = properties;
}
#GetMapping("/test")
public String index() {
System.out.println(buildProperties.getVersion());
System.out.println(buildProperties.getArtifact());
System.out.println(buildProperties.getGroup());
System.out.println(buildProperties.getName());
System.out.println(buildProperties.getTime());
return "index";
}
}
And dont forget generate application-build.properties
springBoot {
buildInfo()
}

Cucumber Test a Spring Boot Application

Does anyone know where I can find a sample application where Cucumber is used to test a Spring Boot application through Gradle? I can run the tests fine starting the server on the cmd line and using my IDE, but I need to be able to run them all programmatically on the CI server. I saw the answer on here but that solution did not work for me, most likely because I have multiple step def files.
Here is my setup
build.grade (Mentioned in the other question)
testCompile ("org.springframework.boot:spring-boot-starter-test",
...
"info.cukes:cucumber-spring:${cucumberVersion}")
CucumberTest.java
#RunWith(Cucumber.class)
#CucumberOptions(format = "pretty", features = "src/test/resources")
public class CucumberTest{
}
AbstractSpringTest.java (Extended by all the StepDef files)
#SpringApplicationConfiguration(classes = Application.class)
#RunWith(SpringJUnit4ClassRunner.class)
#Ignore
public abstract class AbstractSpringTest
{ ... }
It's not doing the correct thing on start up because its 1. trying to initialize my step def files and 2. My application is not started and the cucumber tests cannot make a connection.
Thanks.
EDIT: Or if someone can tell me how to start and stop the application using gradle, that would be acceptable as well.
I have solved the issue with some help from this question.
Here is the repository with the answer:
https://github.com/jakehschwartz/spring-boot-cucumber-example
In short, the AbstractSpringTest class needs to have the following annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = DemoApplication.class, loader = SpringApplicationContextLoader.class)
#WebAppConfiguration
#IntegrationTest
I had a similar symptom, my cucumber wouldn't start up the Spring context...
Turns out I had missed (one of) the following dependencies:
build.gradle
testCompile "info.cukes:cucumber-junit:1.2.4"
testCompile "info.cukes:cucumber-java:1.2.4"
testCompile "info.cukes:cucumber-spring:1.2.4"
StepDefs.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
loader = SpringApplicationContextLoader.class,
classes = Application.class
)
#WebIntegrationTest(randomPort = true)
public class StepDefs {
#Value("${local.server.port}")
int port;
}
Update: SpringBoot 1.5.1
#ContextConfiguration(
loader = SpringBootContextLoader.class,
classes = Application.class
)
Further to #jakehschwartz, if you want the web app to start on a random available port, AbstractSpringTest needs:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
#WebIntegrationTest({"server.port=0"})
public abstract class AbstractSpringTest {
#Value("${local.server.port}")
protected int serverPort;
...}
I did something like this to get Spring to work with JUnit parameterized tests. It should be the same concept for Cucumber, but I haven't tried it. I was using XML configuration, so that might make a difference.
RunWithSpringJUnit4
public abstract class RunWithSpringJUnit4 {
private TestContextManager testContextManager;
public RunWithSpringJUnit4() {
try {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
CucumberTest
#RunWith(Cucumber.class)
#CucumberOptions(format = "pretty", features = "src/test/resources")
public class CucumberTest extends RunWithSpringJUnit4 {
}
First, you'll need to ensure that you have applied spring-boot in gradle. Invoke gradle build which will produce a runnable jar. Instead of having your manifest call for the Spring class as your main, have a wrapper that starts it in a thread, waits for it to settle down and runs Cucumber:
#RunWith(Cucumber.class)
public class LucasePsCucumberTest implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(this);
t.start();
// wait for t
cucumber.api.cli.Main(null);
}
}

Infinitest fails but Maven works

I have Sprint Tool Suite 3.3 and the latest version of Infinitest installed. According to Infinitest, many of my classes have errors, but yet Maven builds just fine. Here is an example of some errors that the Problems tab in STS show:
InvalidDataAccessResourceUsageException (Table "ADDRESSTYPEREF" not found; SQL statement:...SeedAddressTypes.java /... line 34 Infinitest Test Failure
AssertionFailure (null id in com..model.base.Menu entry (don't flush the Session after an exception occurs)) in TestMenuBuilderIT.sortByTopMenu TestMenuBuilderIT.java
All the tests that show an error are integration that use Java Config for the EmbeddedDatabase:
public class TestMenuBuilderIT extends BaseItegration {
#Autowired
private MenuRepository menuRepository;
#Test
public void sortByTopMenu() {
List<Menu> testMenu = menuRepository.findAll(); <== offending line
...
}
And the configuration class:
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( loader = AnnotationConfigContextLoader.class, classes = { JpaConfig.class } )
public abstract class BaseItegration {
..
}
#Configuration
#EnableTransactionManagement
#ComponentScan( basePackages = { ...} )
#ImportResource( { "classpath:applicationContext.xml"} )
public class JpaConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType( EmbeddedDatabaseType.H2 ).setName( "testdb" )
.addScript( "classpath:embeddedDatabase.sql" ).build();
}
I don't see why this would work fine in Maven, but Infinitest has these DB related errors. I could not find any documentation saying that JavaConfig wouldn't work with Infinitest. I am able to right click and run each test "As A Unit Test" successfully.
Does anyone know what might cause this?

Categories