Spring Boot Service using Jpa repository Testing - java

I want to test a Spring #Service.
This service has method using a JpaRepository autowired.
That is the code of the simple service.
#Service
public class PersonneService {
#Autowired
PersonneRepository personneRepository;
public Personne createPersonne(Personne personne) {
return personneRepository.save(personne);
}
I am trying to test it but i have an error
Unsatisfed dependency expressed for the service.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.symit.gmah.emprunt.services.PersonneHandleService': Unsatisfied dependency expressed through field 'personneService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.symit.gmah.emprunt.services.PersonneService' available: expected at least 1 bean which qualifies as autowire candidate. .....
That is the code of my test.
#RunWith(SpringRunner.class)
#DataJpaTest
public class PersonneHandleService {
#Autowired
PersonneService personneService;
#Test
public void PersonneServiceCreateTest() {
Personne personne = new Personne("John","Doe","43343");
personne = personneService.createPersonne(personne);
assertNotNull(personne.getId());
}
Can you help me and explain me what I have to do.
Thanks
PS: I am using embeded H2 Database;
That is my configuration:
# Enabling H2 Console
spring.h2.console.enabled=true
jdbc.driverClassName=org.h2.Driver
#jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jdbc.url=jdbc:h2:~/gmahdb;DB_CLOSE_DELAY=-1
jdbc.username=sa
jdbc.password=sa

You still have to add your services to the Spring context. You now only setup your JPA (entities and repositories).
As an alternative, you could also just use #SpringBootTest in stead of #DataJpaTest. This loads the entire application for testing.
Depending on the size and number of dependencies of your application this might not be the optimal scenario.
From the documentation of DataJpaTest:
Annotation that can be used in combination with
#RunWith(SpringRunner.class) for a typical JPA test. Can be used when
a test focuses only on JPA components. Using this annotation will
disable full auto-configuration and instead apply only configuration
relevant to JPA tests.
and...
If you are looking to load your full application configuration, but
use an embedded database, you should consider #SpringBootTest combined
with #AutoConfigureTestDatabase rather than this annotation.

Related

Bean parameter could not be found when migrating spring boot

I'm migrating services from spring boot 1.5 to spring boot 2.1 and I'm getting an error during this process. I have the following class for configuring my spring beans:
#Configuration
public class CompanyTransactionConfiguration {
public CompanyTransactionConfiguration() {
}
#Bean
public TransactionTaskRunner transactionTaskRunner(PlatformTransactionManager transactionManager) {
return new TransactionTaskRunnerImpl(this.readWriteTransactionTemplate(transactionManager), this.readOnlyTransactionTemplate(transactionManager), this.newReadWriteTransactionTemplate(transactionManager));
}
}
And, of course, a test class to check that everything work as expected:
#RunWith(SpringRunner.class)
public class ReferrerActivityRepositoryIT extends AbstractDomainIT {
#Autowired
private ReferrerActivityRepository referrerActivityRepository;
#Autowired
private TransactionTaskRunner transactionTaskRunner;
...
}
The issue is that this test was working fine after I changed my dependencies to a newer spring boot version (2.1), but now I'm getting the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method transactionTaskRunner in com.company.core.server.config.CompanyTransactionConfiguration required a bean of type 'org.springframework.transaction.PlatformTransactionManager' that could not be found.
The following candidates were found but could not be injected:
- Bean method 'transactionManager' in 'DataSourceTransactionManagerAutoConfiguration.DataSourceTransactionManagerConfiguration' not loaded because #ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans
- Bean method 'kafkaTransactionManager' in 'KafkaAutoConfiguration' not loaded because #ConditionalOnProperty (spring.kafka.producer.transaction-id-prefix) did not find property 'spring.kafka.producer.transaction-id-prefix'
...
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.transaction.PlatformTransactionManager' in your configuration.
I don't know what is going on, maybe I need to add another dependency because of changes in spring boot or change my application.properties file. The question is why is this happening? What should I change to get this working?
Thanks!
You didn't define PlatformTransactionManager bean. I assume you don't want to make it by yourself. You have to add spring.kafka.producer.transaction-id-prefix property to property file in order to use KafkaAutoConfiguration for PlatformTransactionManager.
Bean method 'kafkaTransactionManager' in 'KafkaAutoConfiguration' not loaded because #ConditionalOnProperty (spring.kafka.producer.transaction-id-prefix) did not find property spring.kafka.producer.transaction-id-prefix
By the way your's CompanyTransactionConfiguration constructor is redundant as long as it doesn't have parameters. If there's no constructor in class compiler will create default one without parameters.

spring boot scanning and injecting external non-spring beans

What does it take, or is it even possible for Spring to scan and inject non-spring annotated classes? For example.
resource.jar
com.project.resource.ResourceInterface
com.project.resource.StandardResource <-- concrete implementation
#Singleton <--- Standard CDI annotation
public class StandardResource implements ResourceInterface{
#Override
public void something(){}
}
Now let's say I have a spring boot application which depends on resource.jar.
com.project.resource.SpringApp
#SpringBootApplication(scanBasePackages = {"com.project"})
#EnableAutoConfiguration
public class SpringApp{
... initializer
#Inject
private ResourceInterface resourceService; <--- this is not found
}
Is this supposed to work out of the box? Is this even possible? I'm using spring boot 2.0.0.RELEASE. I'm getting the following error:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'MainController': Unsatisfied dependency expressed through field 'resourceService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.project.resource.ResourceInterface' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#javax.inject.Inject()}
Thanks
For Spring framework #Singleton has no meaning, as such even if class is picked up by component scanning it's going to be ignored. In order for Spring to recognize your class you can:
Create a configuration class in com.project.resource with #Bean of
ResourceInterface and instantiate it as StandardResource.
Since you are using Spring Boot you can create Auto-configuration (which will be similar to the first option) in resource.jar. You can follow examples
from creating autoconfiguration. With this approach no changes needed in com.project.resource
After that your spring boot app will run normally

Spring Boot trying to create mongo repositories in tests using #JsonTest annotations

I have an application using SpringBoot2 with mongodb and I am trying to test json serialization of some DTOS by making tests like:
#JsonTest
#RunWith(SpringRunner.class)
public class SomeDTOTest {
#Autowired
JacksonTester < SomeDTO > json;
#Test
public void someTest() {}
}
However underneath spring is trying to create repository bean and giving me informations:
***************************
APPLICATION FAILED TO START
***************************
Description:
A component required a bean named 'mongoTemplate' that could not be found.
Action:
Consider defining a bean named 'mongoTemplate' in your configuration.
I have more integration test that is using the repository and are annotated with #SpringBootTests and they are working fine...
Is there a way of restricting spring to only creating JacksonTester bean?
You could just create a test without spring runner.
This is an example example test
When loading the spring context if there is an autowired annotation of a mongotemplate somewhere spring will try to provide it. You might consider:
Provided mongo template in tests
Try using #DataMongoTest which will provide an embedded database.
Set an Autowired not required
Use #Autowired(required= false)
Mock mongotemplate
Use #MockBean annotation in order to mock mongoTemplate
I found it quite challenging to have both Integration tests as well as Unit tests in a Spring Boot application.
I checked Spring website and tried many solutions. The one that worked for me was to exclude the AutoConfiguration classes:
#RunWith(SpringRunner.class)
#JsonTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class JsonTests {
#Autowired
private JacksonTester json;
#MockBean
private MyRepository repository;
#MockBean
private MongoTemplate mongoTemplate;
#Test
public void someTest() {}
}
You can find a complete Spring Boot application that include Integration and Unit tests here.

Spring test with #DataJpaTest can't autowire class with #Repository (but with interface repository works!)

I'm trying to understand why I can't autowire a class repository but I can autowire a interface repository in the same package for the same test. The same repository works as expected when I start the application.
First, the error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.app.person.repository.PersonRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.raiseNoMatchingBeanFound(DefaultPersonbleBeanFactory.java:1493)
at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.doResolveDependency(DefaultPersonbleBeanFactory.java:1104)
at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.resolveDependency(DefaultPersonbleBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 28 more
I have a very simple example. The test:
#RunWith(SpringRunner.class)
#DataJpaTest
public class PersonRepositoryTest {
#Autowired
private PersonRepository personRepository; // fail...
#Autowired
private PersonCrudRepository personCrudRepository; // works!
#Test
public void findOne() {
}
}
The repository class:
#Repository
public class PersonRepository {
//code
}
The repository interface:
#Repository
public interface PersonCrudRepository extends CrudRepository<Person, Long> {
}
After a bad experience with this same error, I'm trying to find some detail in my configuration or test what is responsible for this problem. Another possibility is the #DataJpaTest does not have support for class repositories.
I think I was right about the problem. After find a post on Github and read the Spring Documentation:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
My PersonRepository is considered a regular #Component, because it is not a Spring Data JPA repository (the interface is). So, it is not loaded.
The alternative solution is to use #SpringBootTest instead of #DataJpaTest.
The disadvantage with this solution is that will load all your context while running your test and, with this, disabling the test slicing. But do the job.
Another option, still using #DataJpaTest, is include a #Repository filter annotation, like this:
#DataJpaTest(includeFilters = #ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class))
Just another alternative might be #Import as shown here https://stackoverflow.com/a/41084739/384674.

Java Spring JPA Repository

I'm a Spring noob and I'm struggling with it.
Basically before starting develop my Server with Spring in conjunction with JPA I tried to start a simple example just to get used to this framework.
I've already get succeded in make Spring working with some frameworks as Log4J, Swagger and others. Now I'm trying to work with JPA and there are some points i can find out the solution.
I saw some blogs on how to develop with it and from all thousands options i choose to create my Repository Interfece and extend Repository<T, ID>. You can see my code bellow:
package com.example.model;
#Entity
public class Person {
#Id
public Integer id;
public String name;
public Person(){}
}
package com.example.repository;
public interface PersonRepository extends Repository<Person, Integer> {
Collection<Person> findAll();
}
package com.example.controller;
#RestController
public class PersonController {
#Autowired
private PersonRepository repo;
#RequestMapping(value = "/persons", method = RequestMethod.GET)
public Collection<Person> getAll() {
return repo.findAll();
}
}
package com.example;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
And I also have the application.properties file:
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/test_db
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.postgresql.Driver
When I put the server running I get the following exception:
: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.repository.PersonRepository com.example.controllers.PersonController.repo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.repository.PersonRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations:
: Closing JPA EntityManagerFactory for persistence unit 'default'
: Stopping service Tomcat
: Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.repository.PersonRepository com.example.controllers.PersonController.repo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.repository.PersonRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I created a Github Repository to share the code here.
Any clue about what am I doing wrong?
First thing here is why you need to implements the base interface Repository as doing so, you will not have usual CRUD operations. For such operations is better to implements CrudRepository. Since you implement CrudRepository no need to define a findAll() Method and many well known others you can find in doc mentioned.
Furthermore, when using #SpringBootApplication Spring boot use default values. If you see the #SpringBootApplication definition you will see that :
Many Spring Boot developers always have their main class annotated with #Configuration, #EnableAutoConfiguration and #ComponentScan. Since these annotations are so frequently used together (especially if you follow the best practices above), Spring Boot provides a convenient #SpringBootApplication alternative.
The #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan with their default attributes: [...]
That means when using default values for ComponentScan your packages sturctures shloud be as following :
com.example.model -> your entities
com.example.repositoriy -> your repositories
com.example.controller -> controllers
com.example -> MainApplication class
Here is an example for default project structure
The main Application Class should be in higher level package then the others. Unless you have to specify packages location with #ComponentScan.
As you are beginner with the framework. I suggest you to always see classes definitions in official documentation.
UPDATE :
Here is an example from one of my spring boot projects
Also see this spring guide for JPA
Just annotate your interface with #Repository. And if that doesnt work try adding #EnableJPARepositories to the main class.
Try adding the #Repository annotation to your PersonRepository, that could be the reason it doesn't find it.
You need to annotate your PersonRepository interface with #Respository, otherwise the spring context won't recognize it or create an implementation for it.

Categories