Spring Test. Get access of test class of dependent project? - java

I have multi module projects; I am creating Junit Test classes for testing purpose.
But the problem is, when I run my Core Project Test using only 2 package ComponentScan for testing. It is not able to locate Util Project Test config.(Test package get excluded while building JAR)
Because of this, I am getting, No qualifying bean of type exception as Configuration class is missing from Util project.
#SpringBootApplication
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = { CreateProfileTest.class })
#ComponentScan({"com.myproject.testconfig","com.myproject.module"})
#EnableAutoConfiguration
public class CreateProfileTest {
#Test
public void myMethod()
{
}
}
So, How I can gain access to Util Project Test Config in Core Project Test.
Job - > Core -> Util (Here Core is depend on Util)
Now
CoreProject/
src/main/com.myproject.config
src/main/com.myproject.module
src/test/com.myproject.testconfig
UtilPorject/
src/main/com.myproject.config
src/main/com.myproject.module
src/test/com.myproject.testconfig
Please let me know, If there is any alternative way to achieve this or if I am doing anything wrong here.
I am using Maven and Spring Boot.

It seems to me this is a matter of classpath. Have you tried adding this in the CoreProject pom.xml ?
<dependency>
<groupId>...</groupId>
<artifactId>util-project</artifactId>
<version>...</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>

Related

Spring boot integration test with environment variables

I'm working on a multi-module maven project using Java 8, Spring Boot 2.4.0. I want to test one of a module that is calling a 3rd party service. I'm using wiremock to mock that 3rd party service call and have created a spring boot integration test class. My class is in the same package where my XYZService class is. My test is in src/test/... and looks like this.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = SpringApplicationClassWithMainMethod.class)
public class XYZServiceIntegrationTest {
#Rule
public WireMockRule externalService = new WireMockRule();
#Test
public void test1() {...}
#Test
public void test2() {...}
}
When I run the maven build in my eclipse (clean + install). My build is not detecting the tests present at the maven-module where the Integration test is located. The other unit tests in the same module are also not being detected (Note: before adding the integration test class, the unit tests were working). Maven says Tests ran: 0. The integration test is working fine when I Right click on the file and run as JUnit test(Junit 4). Also, I have some environment variables that need to be set for running the SpringApplicationClassWithMainMethod.class that I'm setting within the configurations of that Integration test class in order to successfully load the Application context(I tried to load the environment variables through code and nothing from other stack-overflow posts worked). One more thing to inform my maven only uses Maven surefire plugin for running tests. I dont know if we need to have Maven fail safe plugin for my purpose(Is my test considered a Integration Test when I added the 2 annotations on top of the test class?). Can someone please help me with any suggestions on how to build the parent project.
Adding the maven-failsafe-plugin into my child pom worked. In the parent pom I added the execution goals for maven-failsafe-plugin in the and in the child pom I inherited that plugin.

Spring Integration Testing does not pick up JPA beans from other modules

I have a multi module maven project. In one module I have all my persistence stuff like entities and repositories and in another module I import that persistence module and I want to run some integration tests.
The problem is that my tests do not pick up repositories and can't create the context because of the missing beans. Can someone help me with what I am missing?
The project structure looks like this
persistence module
business logic module
web module
In my business logic module pom I import the persistence module
<dependency>
<groupId>com.acme</groupId>
<artifactId>persistence</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
My integration tests configuration
#Configuration
#ComponentScan({"com.acme.persistence", "com.acme.business"})
#EnableAutoConfiguration
public class DataTestConfig {
}
and all my tests are annotated with the following
#SpringJUnitConfig(DataTestConfig.class)
#DataJpaTest
If I move all the persistence module inside the business module then the tests work fine, but I want to keep them in separate modules.
Thanks
I found the solution.
I added #EnableJpaRepositories on my test configuration class.
This way repositories were created and now my services that used repositories can be instantiated.
This is how the final integration testing configuration looks like
#Configuration
#ComponentScan({"com.acme.persistence", "com.acme.business"})
#EntityScan("com.acme.persistence")
#EnableJpaRepositories(basePackages = "com.acme.persistence")
#EnableAutoConfiguration
public class DataTestConfig {
}

Spring integration test module running app from separate module without properties for DB config

Given a spring boot gradle module named "md-core" with a Spring application runner and a PostgresDbConfig to connect it to the DB.
The app runs perfectly fine and resolves the properties from the "application.yml" file in the #Config.
#Value("${db.default.pool.size}")
Integer maxPoolSize;
Now, a separate module called "integrationtests" tries to launch the Spring Boot Runner in the "md-core" module.
#ContextConfiguration(classes = {MdCore.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class GivenTest
The test launches the "md-core" Spring runner, but when trying to resolve the properties in the #Config, it does not find any properties.
I've tried directly resolving the "application.yml" in the test. It does not send the properties over to the "md-core" module. Any attempt of adding the "application.yml" properties in the test resolves them to the test file, but does not send them over when the "md-core" module is accessed.
Are there any definitions which should be given in the test via annotations or in the gradle build files?
The classpath when launching the test does not contain the "md-core" resources location, only the classes.
Could this be a reason? If yes, how can the resources be referenced in the classpath of the gradle build files?
I apologize for any mistakes or incomplete information, this post is being written at the end of a work day, hoping there will be answers by morning.
Given this situation, the solution to use the application.properties file for the integration test is the simple addition of initializers = ConfigFileApplicationContextInitializer.class in the #ContextConfiguration annotation of the Test class:
#ContextConfiguration(
initializers = ConfigFileApplicationContextInitializer.class,
classes = {SomeApp.class})
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
public class SomeIntegrationTest {
#Test
public void testTheIntegration() {
// some integration tests here
}
}
Answer also documented in a post on my blog and initially found less detailed on another stackoverflow question.

How to test Maven module project with Spring Boot

I have split a project, based on Spring Boot, into several Maven modules. Now only the war-project contains a starter class (having a main method, starting Spring), the other modules are of type jar.
How do I test the jar projects, if they don't include a starter?
Example JUnit test case header:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(StarterClassInDifferentProject.class)
...
I think context tests should be available per module so you can find issues with wire and configuration early on and not depend on your full application tests to find them.
I worked around this issue with a test application class in the same module.
Make sure this main class is in your test dir.
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
your context should work now.
#RunWith(SpringRunner.class)
#ActiveProfiles(profiles = {Profiles.WEB_REST})
#WebMvcTest(EntityController.class)
#DirtiesContext
public class ServicesControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private Controller controller;
#Test
public void testAll() throws Exception {
given(controller.process(null)).willReturn(null);
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
I solved a similar situation.
I have a project with two modules:
a "lib" project with domain and utilities classes,
a "web" projects with a spring boot application, templates, controllers, etc...
and I wanted to test the "lib" project in a spring-boot-test fashion.
First, include the required dependencies with scope "test" in the pom.xml (in my case there is also the H2 database):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.3.3.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- add also add this here, even if in my project it is already present as a regular dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.3.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
<scope>test</scope>
</dependency>
For testing purposes, among the test sources of the "lib" project, I have a class that acts as my test configuration
package my.pack.utils;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#TestConfiguration
#EnableJpaRepositories(basePackages = {"my.pack.engine.storage", "my.pack.storage"})
#EntityScan(basePackages = {"my.pack.storage", "my.pack.entity"})
#EnableAutoConfiguration
public class MyTestConfiguration
{
}
This sets up the H2 database in order to test the data access functionalities of the application
Finally, only in the test classes where I find it useful, I configure the execution to use the test configuration (I do not always need to do that, but sometimes it is handy):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyTestConfiguration.class)
public class TestAClassThatNeedsSpringRepositories
{
// tests...
}
The question is
How do I test the jar projects, if they don't include a starter?
I believe the right answer, is that your jar submodules should not be united tested with spring-boot context.
In fact, most if not all tests in your jar projects should not even use the RunWith(Spring...)
They should be vanilla or using a mock library such as #RunWith(MockitoJUnitRunner.class).
If you read SpringApplicationConfiguration's javadoc:
Class-level annotation that is used to determine how to load and configure an ApplicationContext for integration tests.
It is considered integration testing.
Other than that, you can also launch your tests using spring context (not spring-boot) with a 'test spring configuration' in your jar submodule. Define your beans/resources and use it in your test.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(TestConfigInJarModule.class)
For instance, I do this to test Spring data Repositories, using a test spring configuration (without dependencies on spring-boot).

embedded mongo + spring configuration unit tests fail en masse (failed to load application context)

I'm not sure if this is a embedded mongo issue or a a spring configuration issue, maybe someone else has had the same problem.
I have a spring+maven project set up in Intellij, and have embedded mongo in test scope.
The problem: When I right click on the test java folder to run all tests, I get the dreaded application context error (see below for details). However running tests individually, or even package by package is fine. I have discovered that there is 1 test (coincidentally the first one that runs in the entire set) that is causing the break, and if I delete it I can run all tests again. Let's call this TestA. I'd like to understand why this one test causes all others to fail, and how to fix it (Since i'd really like to have that test!).
All tests extend a base class that starts with this (except for TestA):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Config.class, MongoConfig.class})
#WebAppConfiguration
#IntegrationTest("${port}")
#Component
TestA is slightly different because it doesn't need Mongo to run, but does need spring to autowire the services. I thought this would be ok, but it's not:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Config.class})
#Component
MongoConfig.class is simply annotated:
#Configuration
#EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
#EnableMongoRepositories(basePackages = "<my package>")
plus the #Beans for creating the mongo process.
Config.class has these annotations and en empty body:
#Configuration
#EnableAutoConfiguration(exclude = {EmbeddedMongoAutoConfiguration.class})
#ComponentScan(value = {<list of packages>})
#EnableMongoRepositories(basePackages = {"my package"})
However if i try to run all the tests they all fail with the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext
<huge stack trace eventually ending with...>
Caused by: java.nio.file.FileAlreadyExistsException: C:\Users\john\AppData\Local\Temp\extract-john-extractmongod.exe
at sun.nio.fs.WindowsFileCopy.copy(WindowsFileCopy.java:124)
at sun.nio.fs.WindowsFileSystemProvider.copy(WindowsFileSystemProvider.java:278)
at java.nio.file.Files.copy(Files.java:1274)
at de.flapdoodle.embed.process.extract.ExtractedFileSets.copy(ExtractedFileSets.java:54)
at de.flapdoodle.embed.process.store.ExtractedArtifactStore.extractFileSet(ExtractedArtifactStore.java:110)
at de.flapdoodle.embed.process.runtime.Starter.prepare(Starter.java:56)
... 192 more
My understanding is that somehow by adding TestA embedded mongo is trying to start up every time?
My temporary solution is to delete the annotations in TestA and extend the base class described above. That makes it all work fine, but isn't really correct. What I need is the right annotations on TestA for it to work in tandem with the rest of the tests.
dependencies
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.50.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
spring configuration
I don't use xml files, rather I set up class Configuration files tied up with yml files (facets added to module in Intellij).

Categories

Resources