DataJpaTest looking for HttpServletRequest - java

I have a question about the usage of DataJpaTest annotation. I am trying to test a Jpa repository, exactly as shown in the documentation.
I am getting an error that the HttpServletRequest cannot be resolved. It is because a different bean of mine is using it.
Why is the test trying to use the irrelevant bean? I would expect a DataJpaTest to only load Jpa related beans, repositories, etc. It seems it is trying to load all beans, which of course have their own dependencies.
What is the correct way to write a DataJpaTest so that I only focus on my Jpa repositories?
This is on Java 8, Spring Boot 2 and junit 5.
Update 1: thanks for the comments guys. My test class is literally based on the documentation.
My Spring Boot application class is like this:
#SpringBootApplication
#EnableSwagger2
#EnableCorsFilter
#ComponentScan(basePackages = {"com.acme.superapp"})
#SuppressWarnings("HideUtilityClassConstructor")
public class Swagger2SpringBoot {
public static void main(String[] args) {
new SpringApplication(Swagger2SpringBoot.class).run(args);
}
}
This actually helped because after I removed the "ComponentScan" annotation I get a different error, related to Swagger.
So it seems these annotations are affecting my test.

Thanks for your comments guys. The comment from M. Deinum and shinjw showed me to the correct path. I needed to slim down the entrypoint so that it does not have anything extra.
According to the documentation :
If you structure your code in a sensible way, your
#SpringBootApplication class is used by default as the configuration
of your tests.
It then becomes important not to litter the application’s main class
with configuration settings that are specific to a particular area of
its functionality.
Therefore I moved the ComponentScan and EnableSwagger2 annotations elsewhere, in different Configuration classes and this did the trick.
Thanks for your help!

Related

Internal Implementation of IOC and DI in Spring Boot

Whenever spring boot application runs it sees the #SpringBootApplication annotation and runs the #ComponentScan which scans the classes with the annotations such as #Component etc and makes the object in the container.I have a little bit of idea that it might be using reflections internally to create the objects but I am not able to connect all the dots .I want to know what exact information does #AutoConfiguration gives to the container that it is able to get all the information of all the component annotated clases of any component ?
P.s. I have edited the wrong question
First of all #AutoConfiguration is responsible for setting up the default configurations for a Spring boot application depending on the dependencies we have added in the pom.xml.
The thing you are looking for is #ComponentScan which is what performs the component class scanning within the default package and all of its sub packages. It does this by going through each class in the package and looking for the #Component,#Service or #Repository annotations. If any of them is present then the container adds this as a bean.
#SpringBootApplication internally has the #ComponentScan annotation added to it along with two others.

How can I inject dependency from a library in Spring Boot 2?

I have a library in which I defined a class let's say MyClass with #Component along with #Value but when I try to use this in my Spring Boot application and try to Autowire it, I get exception about Spring not being able to find this type and ask me to define a Bean. All other classes gets injected just fine that I have defined in the application it self.
How can I make the MyClass to be injected?
Without a complete information on about your library, how you are using it, we can't provide solution. Assuming everything on your library is correct, you can simply add #ComponentScan on the application that use your library.
Create a class as below and that should fix your problem.
#Configuration
#ComponentScan({"your library package"})
public class YourConfig {
}
If this doesn't solve your problem, add more information on your question and I will update my answer accordingly.

How to find entry point of a Spring Boot application?

What is the entry point of a spring boot application?
While going through a Spring Boot application code, all that it says is there is a code
public static void main having - SpringApplication.run(Application.class, args)
Example - SpringBoot2RestServiceApplication.java .
But how to get to know what is the entry point, just by going through the code. Earlier, if we go through applicationContext.xml - example - applicationContext.xml, we could understand the flow.
Is there any way, or maybe a standard to follow to make this understanding self-explanatory?
My question was more of understanding the flow of the application than finding the main class. One option could be separating configurations(#Configuration) to a separate class having multiple #Bean annotations, this would help in finding all bean wirings at one place. Is there a standard that large projects use to make code flow understandable?
The easiest thing to do would probably be to search for #SpringBootApplication in your code.
But, a guaranteed way to get this information would be to build the Spring Boot JAR. From there, you can open the resulting JAR and find the main class defined in the manifest, under META-INF/MANIFEST.MF. You'll see it under the Start-Class attribute:
Start-Class: com.example.foo.Application
I think the OP is studying an existing Spring Boot application, and is asking how to locate any runner, such as Application Runners, Command Line Runners, MVC controllers, Rest controllers, etc.
I don't know if there is an easy way to locate those, unless they are grouped together in the original design.
It's a difficult problem to do programmatically, because threads can be launched outside of Spring, for example in a constructor or a #PostConstruct.
It would be nice though if there were IDE support to easily locate anything that gets launched by Spring Boot
search #SpringBootApplication annotation in your project, the class with #SpringBootApplication annotation will automatically do the component-scan for the sub packages.
if no #SpringBootApplication annotation found, search the class extending "SpringBootServletInitializer" which is also a starting point for the spring boot application
The Entry of any spring boot application has an annotation of #SpringBootApplication

Spring boot and Flyway: Clear database data before integration tests

I'm building a REST service using Spring boot framework (v2.0.2), where I have integration tests running on a database. I googled a lot and there is a sea of articles about cleaning database before tests, but unfortunately I find them either inefficient or a hack and not for Spring boot. Could you, please, bear with me and suggest a good way for this problem?
Ideally, I think the database should be cleared not before each test, but before some group of them, like suite or maybe each test class. One of the found suggestions looks like this:
#Autowired
protected Flyway flyway;
#Before
public void init() {
flyway.clean();
flyway.migrate();
}
which rebuilds database before each test and clearly is not efficient. Changing this to static context and using #BeforeClass does not work as Spring does not inject static fields.
Is there some nice way to reach this flyway bean from static context, to make this solution work?
Sub-question here: Flyway has a command clean, which not only clears data, but drops everything and then migrate command performs migrations again. This also seems like overhead. As the migrations are checked at startup anyway, I don't see the necessity to tear down and rebuild everything before each test group. Just clearing data would be sufficient. Would you give some advice about how this can be achieved?
To sum up, I'm looking for a standard way of removing the database data (and not tables if possible) before each group of integration tests (e.g. per class). I suppose everybody faces this task while using Spring boot, so maybe there is some nice solution considered in the framework itself.
Thank you!
You could create configuration file for your tests. It would run one time before all tests.
#Configuration
public class TestConfig {
#Bean
public FlywayMigrationStrategy clean() {
return flyway -> {
flyway.clean();
flyway.migrate();
};
}
}
This answer was useful but it didn't get me all the way there and so I thought I'd come back and add an answer in case someone else was looking to solve this same issue. The bean definition above was terrific.
There are spring profiles of which there are 5 or so possibilities. I looked at the docs and how people use them but went another route. Maven has 6 scopes, but the ones which are useful in this case are runtime and test.
As I dug into the spring profiles and the various ways one can switch between them it seemed for my situation a bit too complex. I just want my database under test to be created, scructured and populated with some data so I can test the repositories in my jpa spring boot app. I don't want to spend 4 hours setting up profiles. Not that it isn't a worthy endeavor in the long run, just that I wanted to get things moving.
When I execute spring-boot:run, I want the non-test db to be migrated but I don't want any crud data in there that I use for testing.
So, in the live app I want a virtually empty database and during tests, I want flyway to clean the db, run the versioned migrations and populate it with test data.
The answer above led me to a solution which I will probably fold into spring profiles as my project gets closer to production.
Turns out that spring-boot-test provides a #TestConfiguration annotation which you can attach to any class in the src/test/ hierarchy. I created a FlywayConfiguration class which contains the bean definition provided above:
package com.foo.fooservice;
import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
#TestConfiguration
public class FlywayMigrationConfig {
#Bean
public static FlywayMigrationStrategy cleanMigrateStrategy(){
return flyway -> {
flyway.clean();
flyway.migrate();
};
}
}
So now, if I want to use this in a test, I add another nifty annotation in the appropriate test class- #Includes, a companion to the #TestConfiguration annotation - so that I can use this configuration in the same way I might have used #BeforeClass like so:
#DataJpaTest
#Import(FlywayMigrationConfig.class)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class AccountUserRepoTest {
#Autowired
private AccountUserRepo accountUserRepo;
#Autowired
private FlywayMigrationStrategy strategy;
This allows me to inject this flyway migration strategy on a per-test-class basis. Spring won't auto-inject your bean into every test class and you can use this configuration now just by adding the #Includes annotation to the appropriate test classes. You don't have to define the bean in every test class where you want to use it. Just use #Includes(your#TestCongiguration-annoted-class).
I happen to be using postgresSQL as opposed to H2 because I figure if I'm doing an integration test on the repository entities I might as well do it against what I will be using in production.
Also: src/main/resources has the jdbc and flyway properties set to a dev schema name and jdbc url.
src/test/resources/application.properties sets the schema name to 'test' (you can name it whatever you want).
The one drawback to this approach that you may not want is the granularity- the DB is cleaned and repopulated for every test class which you configure this way.
I personally like this because for each repository class I'm testing I'd like the data to be refreshed. I also like that if I'm working on a particular test class, having the configuration at this level of granularity means that 'run test' works out of the box. No special configuration in the IDE is required to make it work.

Understanding #Enable... annotations concurrency

We have a project that uses spring-boot-cache-starter, registering an ehCache CacheManager implementation, and spreading #Cacheables accross the code.
Then, some other team created an starter, that basically relies on the default configuration autconfigured by spring-boot-cache starter (hashmap) for its own processing of #Cacheable methods.
Both codes contain the #EnableCaching annotation, and our issue is that the behavior is different in case we comment our main project's #EnableCaching annotation.
If we don't comment #EnableCaching in our project, when we use the custom starter, everything works fine. #Cacheables from the
starter are indexed and resolved in the starter scope but
#Cacheables from our domain are resolved in our ehcache.
If we comment #EnableCaching in our project, then both the starter and our project's #Cacheables are tried to be resolved
against our ehCache implementation.
This breaks a lot of preconceptions I had so far:
I always thought an annotation such as #Enable... applied to all the context, regardless of the placement (starter/application configuration), and regardless of whether it was found once or twice when scanning all #Configuration classes.
Why does the case work when both annotations are there, I guess the CacheManager in the spring-boot-cache-starter is a #ConditionalOnBean, so in that case I would expect both projects using the ehcache bean for resolving, not each one's domain
P.S: the #EnableCaching found in our main project is placed on an inner static #Configuration class. Could this be significant?
It is very hard to answer your question if you don't reveal what the custom starter does. In particular, this looks weird to me:
#Cacheables from the starter are indexed and resolved in the starter scope but #Cacheables from our domain are resolved in our ehcache.
Your preconceptions 1 is valid: it doesn't matter where you you put the annotation or if you add it more than once. It will just enable caching for the whole ApplicationContext. In the case of Spring Boot, that will trigger the auto-configuration unless a custom CacheManager bean is defined in user's configuration.
The "each one's domain" sounds broken to me. Are you sure this is what's happening? If you want to store in several cache managers there is not a lot of different ways:
You need to define a CacheResolver and refer to it in the #Cacheable annotations (or #CacheConfig)
You need a special CacheManager that knows where to find the caches in each underlying stores
If each domain has a standard use of #Cacheable it will go against the CacheManager. If you notice the behaviour you are describing, it has nothing to do with #EnableCaching at all.

Categories

Resources