Data Jpa Test fails to load properties - java

I am using Hashi Corp vault in Spring Boot project. I am able to run the project without any issue. But when I run unit tests, secret-id and role-id are not being passed. I tried the following but got an exception saying both are empty. Tried hard coding the values, that didn't work either
EmployeeTest.java
#RunWith(SpringRunner.class)
#DataJpaTest
#ActiveProfiles(value = "ide")
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class EmployeeTest
{
private final Logger logger= LoggerFactory.getLogger(getClass());
#Autowired
EmployeeRepository employeeRepository;
#Test
public void getEmployeeById()
{
Employee employee=employeeRepository.getOne(13L);
logger.info(employee.toString());
}
}
Update:
I am able to pass secret-id and role-id through VM arguments but still properties are not resolving

Okay, it turns out when using profile from src/main/resources/application-ide.yml in spring boot test, properties are not being replaced by vault vaules. Copying the same file to src/test/resources/application-ide.yml fixes the issue.
TL;DR
For Spring Boot testing always better to use properties file from src/test/resources rather than src/main/resources

Related

Spring DATA JDBC fails to inject a Repository when run from the spring integration test

Spring Boot JDBC with Spring Boot: 2.2.4.RELEASE, in gradle the dep:
implementation ("org.springframework.boot:spring-boot-starter-data-jdbc")
The dep to -data-jpa (see "duplicated question")
//implementation ("org.springframework.boot:spring-boot-starter-data-jpa") is commented
Got this error ONLY when run it from the integration tests:
"A constructor parameter name must not be null to be used with Spring Data JDBC!"
Error creating bean with name 'myRepository':
where my repository is defined as this. An interface. It can not have a constructor.
public interface MyRepository extends CrudRepository<MyData, UUID> {
the way it is injected is:
#Inject
MyRepository myRepository;
The integration test itself:
#ActiveProfiles("test")
#ExtendWith(SpringExtension.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
public class MyResourceTest {
It used to work for a lower spring boot version from the tests.
It works Ok. from IDE when starting tests.
It works Ok. when starting the app and hit the endpoints - it does inject the repositories.
Q: How to make Spring DATA JDBC work without this "A constructor parameter name must not be null to be used with Spring Data JDBC!" error for the spring data jdbc repositories?
UPDATE: just checked and double-checked.
class MyData {
//#Id Dont use the Id annotation here because I use a mapper when #Query(.. by this object
private UUID id;
private String name;
private MyData2 mydata2;
public MyData() {}
public MyData(String name, MyData2 mydata2) {...}
.. all getters and setters
}
MyData2 is the same - with the default + all arg Constructor. All is made manual. No lombok.
Update 2:
if I create a folder "jdbc" put there the config class with # EnableJdbcRepositories and move all my data jdbc repositories there "to be in one module". I still have the same exception. IF run from the integration test.

How to overwrite ports defined in application.properties in integration tests after testcontainer started?

Assume I want to integration test code relying on a JPA datasource in a Spring Boot 2.x application with a PostgreSQL testcontainer (great tool for managing Docker containers from within test classes with one or few more lines of code). Assume further that I'm managing the ports (included in the JDBC URL) in application.properties, e.g.
spring.datasource.url=jdbc:postgresql://user-service-postgres:5432/user_service
In the integration test I create testcontainers with
#Rule
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();
In a preparation method I can access the value I want to set for spring.datasource.url with
postgreSQLContainer.getJdbcUrl()
How to tell Spring Boot in the test to use that URL instead of the one specified in application.properties.
I'd like to stick to my property files in order to minimize changes, but I'm thankful for other approaches including an explanation why they're superior or necessary as well.
I'm using Spring Boot 2.x.
Since Spring Framework 5.2.5 (Spring Boot 2.2.6) this setup is now even simpler as we can use the #DynamicPropertySource annotation and don't have to write and register a custom initializer.
Assuming you use the JUnit 5 dependency of Testcontainers, your test can look like the following:
#SpringBootTest
#Testcontainers
class ExampleIntegrationTests {
#Container
static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();
#DynamicPropertySource
static void dataSourceProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
}
}
You can read more about this new feature here. I've also covered the different application properties setup ways (depending on Spring Boot and JUnit version) in a dedicated Testcontainers guide.
You can manually override the property from within your Spring-boot test by using ContextConfiguration and ApplicationContextInitializer.
Override the property - define a static inner class:
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl())
.applyTo(configurableApplicationContext.getEnvironment());
}
}
ApplicationContextInitializer can be used for programmatically initializing a Spring context before context refresh. Now, wire up the context initializer class by annotating at test class level with ContextConfiguration:
#ContextConfiguration(initializers = Initializer.class)
Docs:
ApplicationContextInitializer
ContextConfiguration

Springboot/Cucumber Integration-How to use #Autowired(or other SB tags) inside step definition class?

I'm trying to create a Springboot, cucumber and Junit4 automation framework. The versions I used as below:
Springboot: 2.1.3
cucumber: io.cucumber 4.2.3
Junit4: 4.12
Operating System: Win7 Pro.
I created a prop class which trying to get properties from property file (.yml)
Prop Class:
#Data
#Component
public class PropsConfig {
#Value("${spring.skyewss}")
public String url;
}
Step defs:
public class SkyeWssLoginStepDef implements En {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
private WebDriver driver;
private SkyeWssLoginPage loginPage;
private SkyeWssUtil skyeWssUtil;
#Autowired
private PropsConfig propsConfig;
public SkyeWssLoginStepDef() {
Given("^I open Skye WSS web page$", () -> {
driver = CukeHook.driver;
loginPage = new SkyeWssLoginPage(driver);
driver.get(propsConfig.getUrl());
skyeWssUtil = new SkyeWssUtil();
LOGGER.info("Current page is " + driver.getTitle());
});
}
......
}
Cucumber runner class:
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/resources/features"},
plugin = {"pretty", "html:target/cucumber-html-report"},
tags = {"#SkyeWss"}
)
#SpringBootTest
public class WssRegApplicationTests {
}
I've tried to give tags on stepdef classes, but no luck.
When I give stepdef classes tags like #Component or #SrpingBootTest, I will get error.
cucumber.runtime.CucumberException: Glue class class
com.flexicards.wss_reg.skye.step.SkyeWssLoginStepDef and class
com.flexicards.wss_reg.skye.step.SkyeWssDashboardValStepDef both
attempt to configure the spring context. Please ensure only one glue
class configures the spring context
cucumber.runtime.CucumberException: Glue class com.flexicards.wss_reg.skye.step.SkyeWssDashboardValStepDef was
annotated with #Component; marking it as a candidate for
auto-detection by Spring. Glue classes are detected and registered by
Cucumber. Auto-detection of glue classes by spring may lead to
duplicate bean definitions. Please remove the #Component annotation
I'm new to Spring and Springboot, I'm pretty sure I did not configure correctly in somewhere. Most example for springboot and cucumber out there are outdated. I've tried them already. Like create an abstract classes which extended by all the stepdefs classes. This will give me the same error as #SpringBootTest one.
Could anyone help me on this? Any inputs are welcomed. Thank you very much.
Looks like you've done almost everything right. The only thing out of place is the the location of your context configuration. It has to be in a file with a step or hook definition. Otherwise Cucumber won't detect it. This should do the trick:
#SpringBootTest
#AutoConfigureMockMvc
public class CucumberContextConfiguration {
#Before
public void setup_cucumber_spring_context(){
// Dummy method so cucumber will recognize this class as glue
// and use its context configuration.
}
}
You can find a working example of cucumber-spring in the cucumber github repository.
Perhaps also worth to keep in mind that Cucumber implements step definitions as spring beans rather then post processed unit test classes as you might expect. This means that #MockBean, #SpyBean and friends won't work.
edit:
With Cucumber v6.0.0 you can omit the dummy method and instead use the #CucumberContextConfiguration annotation.
#SpringBootTest
#CucumberContextConfiguration
public class CucumberContextConfiguration {
}

Spring Boot Test does not use jmx property

I have a test clas with
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class Foo{
...
}
which should start up a regular application context as defined by:
#SpringBootApplication(scanBasePackages = {"de.foo", "de.bar"})
public class Application {
...
}
This works as expected. Further I have an application.yml which gets loaded in both cases but when running the test, the property for JMX (spring.jmx.enabled) does not get loaded or it does not get used.
I tried different property files (application.yml, application-test.yml) but the only thing what works is setting the property via
#TestPropertySource(properties = "spring.jmx.enabled:true")
The property defaults to true in a regular application context.
Several questions:
Why is the default different in a test class?
Why does the property not get loaded or recognized, when loading it from an application.yml (the rest of the yml works, so it does get loaded).
This seems to be a known behavior, as seen in this comment in Spring Boot Sample Data Tests. Is there any documentation I missed about this behavior?
I've recently encountered the same situation myself, and have opened spring-projects/spring-boot#13008 to document this behavior. As a result, the following additions to the reference manual will be added in the upcoming 1.5.13.RELEASE and 2.0.2.RELEASE:
As the test context framework caches context, JMX is disabled by default to prevent identical components to register on the same domain. If such test needs access to an MBeanServer, consider marking it dirty as well:
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.jmx.enabled=true")
#DirtiesContext
public class SampleJmxTests {
#Autowired
private MBeanServer mBeanServer;
#Test
public void exampleTest() {
// ...
}
}

Spring Boot integration tests doesn't read properties files

I would like to create integration test in which Spring Boot will read a value from .properties file using #Value annotation.
But every time I'm running test my assertion fails because Spring is unable to read the value:
org.junit.ComparisonFailure:
Expected :works!
Actual :${test}
My test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebTests.ConfigurationClass.class, WebTests.ClassToTest.class})
public class WebTests {
#Configuration
#ActiveProfiles("test")
static class ConfigurationClass {}
#Component
static class ClassToTest{
#Value("${test}")
private String test;
}
#Autowired
private ClassToTest config;
#Test
public void testTransferService() {
Assert.assertEquals(config.test, "works!");
}
}
application-test.properties under src/main/resource package contains:
test=works!
What can be the reason of that behavior and how can I fix it?
Any help highly appreciated.
You should load the application-test.properties using #PropertySource or #TestPropertySource
#RunWith(SpringJUnit4ClassRunner.class)
#TestPropertySource(locations="classpath:application-test.properties")
#ContextConfiguration(classes = {WebTests.ConfigurationClass.class, WebTests.ClassToTest.class})
public class WebTests {
}
for more info: Look into this Override default Spring-Boot application.properties settings in Junit Test
Besides the above marked correct answer, there is another nature way to load application-test.properties: Set your test run "profile" to "test".
Mark your test cases with:
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
application-xxxx.properties is a naming convention for properties of different "profile".
This file application-xxxx.properties should be placed in src/main/resources folder.
"Profile" is also useful in bean configuration.

Categories

Resources