Injecting Spring Data Repositories in Junit 5 Tests - spring

I am trying to inject a spring data repository in a Junit 5 test but I am getting
No qualifying bean of type 'com.xxx.core.security.datastore.AccountsRepository' available: expected at least 1 bean which qualifies as autowire candidate
here is the test
package com.xxx.core.security.datastore;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
#SpringJUnitConfig
class AccountsRepositoryTest {
#Autowired
AccountsRepository accountsRepository;
#BeforeEach
void setUp() {
Assumptions.assumeTrue(true); // how to get spring profile !
}
#Test
public void name() {
}
}
And here is my repo
package com.xxx.core.security.datastore;
import com.checkit.core.security.datastore.model.Account;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface AccountsRepository extends CrudRepository<Account,Long> {
Account findByName(String name);
}
When I run the application spring seems to wire everything

I solved the issue by including a config class to the annotation and a test property source, in Junit as far as I remember this was not needed as the test configs were by default.
#SpringJUnitConfig(CoreApplication.class)
#TestPropertySource("/application.properties")
class AccountsRepositoryTest {
#Autowired
AccountsRepository accountsRepository;
#BeforeEach
void setUp() {
Assumptions.assumeTrue(true); // how to get spring profile !
}
#Test
public void name() {
}
}

Related

Spring context failed to load in test class if #ComponentScan is from an Interface

I have this behaviour in a spring test that I don't witness running the application.
My test class fail to load OpenElevationClientImpl bean even though the OpenElevationClient interface is mentionned in the annotation #SpringBootTest(classes = {OpenElevationClient.class}).
The purpose of this post is that I cannot explain that the OpenElevationClientImpl bean is correctly loaded if I reference in #SpringBootTest annotation a class with the #ComponentScan annotation from the same package of the OpenElevationClient interface.
The test class
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = {RestClientConfig.class, OpenElevationConfig.class})
public class EnrichmentUtilsTest {
#Autowired
ApplicationContext applicationContext;
#Autowired
OpenElevationClient elevationClient;
#Test
public void printBeans() {
for(String tmp:Arrays.asList(applicationContext.getBeanDefinitionNames())){
System.out.println(tmp);
}
}
}
All the following classes are from the same package.
OpenElevationClient interface: bean is not found if this class is in #SpringbootTest
#ComponentScan
public interface OpenElevationClient {
LocationElevationResultsDTO getElevation(String locations);
}
OpenElevationConfig class: bean is found if this class is in #SpringbootTest
#ComponentScan
public class OpenElevationConfig {
}
OpenElevationClientImpl bean
#Service
public class OpenElevationClientImpl implements OpenElevationClient {
private OpenElevationLookupApi openElevationLookupApi;
#Autowired
public OpenElevationClientImpl(OpenElevationLookupApi openElevationLookupApi, #Value("${openelevation.api.url}") String basePath) {
openElevationLookupApi.getApiClient().setBasePath(basePath);
this.openElevationLookupApi = openElevationLookupApi;
}
#Override
public LocationElevationResultsDTO getElevation(String locations) {
return this.openElevationLookupApi.getLookup(locations);
}
}
Again, this behaviour is only witnessed running the tests and the OpenElevationConfig.class is only used as a component class to use for loading the ApplicationContext in the test class. Anything I missed that could explained this strange behaviour to me?
EDIT 16/12/2021 - repo to reproduce https://github.com/charlycou/stackoverflow-70198445.
Replace OpenElevationConfig.class with OpenElevationClient.class in the test (AppTest) and the test will fail.
Remove OpenElevationConfig.class and run Main.class and the application is running fine
To the original question:
In Ref-doc I see #ComponentScan ONLY on #Configuration classes.
...
But what I could get out of your (git) repo, was:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.262 s - in fr.stackoverflow.example.app.AppTest
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
with this test:
package fr.stackoverflow.example.app;
import fr.stackoverflow.example.api.openelevation.OpenElevationClient;
import fr.stackoverflow.example.api.openelevation.OpenElevationConfig;
import fr.stackoverflow.example.api.openelevation.model.LocationElevationResultsDTO;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = {
OpenElevationConfig.class // c'est ca!
})
public class AppTest {
#Autowired
OpenElevationClient elevationClient;
#Test
public void testBad() {
assertThrows(org.springframework.web.client.HttpClientErrorException.BadRequest.class, () -> {
this.elevationClient.getElevation("dummy");
});
}
#Test
public void testGood() {
LocationElevationResultsDTO elevation = elevationClient.getElevation("41.161758,-8.583933");
assertNotNull(elevation);
assertNotNull(elevation.getResults());
assertThat(elevation.getResults().isEmpty()).isFalse();
assertNotNull(elevation.getResults().get(0));
assertNotNull(elevation.getResults().get(0).getElevation());
assertThat(elevation.getResults().get(0).getElevation()).isEqualTo(117);
}
}
Here is how (see code & git comments).

Why is my configuration test class not working?

I am trying to write unit test using junit for my service configuration class. I have existing code that works in other module, but it doesn't work on this module for some reason and I cannot figure this out. Here is my code:
ServiceConfig class:
package config.service;
import service.Service;
import service.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ServiceConfig {
#Autowired
private Service service;
#Bean
public Service service() {
return new serviceImpl();
}
}
Service interface:
package service;
public interface Service {
void search() throws Exception;
}
ServiceImpl class:
package service;
public class ServiceImpl implements Service {
#Override
public void search() throws Exception {
return null;
}
}
ServiceConfigTest class:
package config.service;
import service.Service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertNotNull;
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { ServiceConfig.class })
public class ServiceConfigTest {
#Autowired
private Service service;
#Test
public void service() {
assertNotNull(service);
}
}
and here is the Exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ServiceConfig': Unsatisfied dependency expressed through field 'Service'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.nuance.powershare.dispatchreporter.service.Service' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't have too much experience with spring and configuration classes. However, this seems legit to me, I basically followed the code that was already working in other module. My manager also cannot find what is wrong.
The above exception is caused, when we did not create a bean of the type it will raise an exception "Error creating bean with name 'className'.
I tried the same code it's working for me. However, you don't need to create Service Config to create a bean of ServiceImpl just annotate ServiceImpl with #Service and you can test it subsequently.
#Service
public class ServiceImpl implements Service {
#Override
public void search() throws Exception {
}
}
and avoid using the predefined names(ex: Service) for the class name.

No qualifying bean of type repository when running test but not main application

I'm developing a Spring Boot application following TDD methodology. I've created the main classes (controller, service and repository) this way:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class CrimeServiceImpl implements CrimeService{
#Autowired
private CrimeRepository repository;
...
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CrimeController {
#Autowired
private CrimeServiceImpl service = new CrimeServiceImpl();
Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CrimeRepository extends JpaRepository<Crime, Long>{
}
This is the project structure:
If I run the application normally, no error. The classes' methods are empty. Then I've created a test class like this:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = CrimeServiceImpl.class)
#ComponentScan("com.springmiddleware")
#AutoConfigureMockMvc
#SpringBootTest
public class TestCrimeService {
//Calling method getAllCrimes works
#Test
public void returnAllCrimesExists() throws NoSuchMethodException, SecurityException {
List<Crime> list = new ArrayList<>();
assertTrue(this.service.getAllCrimes() == list);
}
And if I run this, the following error is shown and the test fails:
NoSuchBeanDefinitionException: No qualifying bean of type 'com.springmiddleware.repository.CrimeRepository' available: expected at least 1 bean which qualifies as autowire candidate.
I've checked all annotations and it seems to me that all is ok, and I thought if I missed something, even in the normal run the application would fail. What did I got wrong?
I wanted also to make a test class for a JPARepository, and I also encountered the same error message:
NoSuchBeanDefinitionException: No qualifying bean of type
'SomethingRepository' available:
expected at least 1 bean which qualifies as autowire candidate.
I could make it work by adding the 2 following annotations on top of the test class:
#EnableJpaRepositories(basePackageClasses = SomethingRepository.class) // repository
#EntityScan(basePackageClasses = Something.class) // entity of the repository
Now it looks like:
#RunWith(SpringRunner.class)
#EnableJpaRepositories(basePackageClasses = SomethingRepository.class) // repository
#EntityScan(basePackageClasses = Something.class) // entity of the repository
#SpringBootTest(classes = MyDbUnitTestApp.class) // does some #ComponentScan and #EntityScan on the repositories/entities package, and #EnableAutoConfiguration
#ActiveProfiles(Profiles.myTestProfile)
#DatabaseSetup(value = {
"/datasets/dataset1.xml" }, type = DatabaseOperation.CLEAN_INSERT)
public class SomethingRepositoryTest {
#Autowired
private SomethingRepository sut;
#Test
public void findById() {
Something something= sut.findById(1L);
Assert.assertEquals("foobar", something.getName());
}
}

How to make Spring IoC container available through out project

I feel stupid to even ask for this but I spent days looking for the answer and I'm still with nothing.
I wanna include simple Spring IoC container in my project. All I want it to do is to allow me Injecting/Autowiring some reusable objects in other classes. What I've done so far looks like this:
-> Project structure here <-
Configuration code:
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
#Configuration
#ComponentScan(basePackages = "com.example")
public class AppConfig {
#Bean
public Random rand() {
return new Random(42);
}
#Bean
public String string() {
return "Hello World!";
}
}
Main class code:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class Main {
#Autowired
Random rand;
#Autowired
String string;
public static void main(String[] args) {
// workflow
Main main = new Main();
System.out.println(main.string);
}
}
AnotherClass code:
package com.example.deeperpackage;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class AnotherClass {
#Autowired
Random rand;
#Autowired
String string;
public void methodToBeCalled() {
// TODO
System.out.println(string);
}
}
How can I make these #Autowired annotations work? Do I have to instantiate container in every single class in which I want to autowire components? I've seen in work a oracle app which used Spring and #Inject to distribute objects to numerous classes and there was no container logic in any class available for me. Just fields with #Inject annotation. How to achieve that?
Simply add the annotation #Component on the classes you want to inject :
#Component
public class AnotherClass {
...
}
But you cannot inject static attributes and when you do new Main(), no Spring context is being created. If you use Spring Boot, you should look at how to write a main with it.
https://spring.io/guides/gs/spring-boot/

No qualifying bean of type found for dependency

I´m tri to run a JUnit Test um my spring boot project i bilded like this:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.br.suppcomm.ocp.entity.Login;
public interface LoginDao extends JpaRepository<Login, Long>{
...
}
Service:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.br.suppcomm.ocp.dao.CompanyDAO;
import com.br.suppcomm.ocp.dao.LoginDao;
import com.br.suppcomm.ocp.entity.Login;
#Service
public class LoginService {
#Autowired LoginDao loginDao;
#Autowired CompanyDAO companyDao;
public void save(Login login) {
loginDao.save(login);
}
public void delete(Login login) {
loginDao.delete(login);
}
public Login findById(Login login) {
return loginDao.findOne(login.getLoginId());
}
public Login findByEmail(Login login) {
return loginDao.findByEmail(login.getEmail());
}
public Login FindByLogin(Login login) {
return loginDao.FindByLogin(login);
}
public List<Login> getAll() {
return loginDao.findAll();
}
public Login getUserAccessLoginPass(String login, String password) {
return loginDao.getUserAccessLoginPass(login, password);
}
public void update(Login login) {
loginDao.save(login);
}
}
Test:
package com.example;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.br.suppcomm.ocp.service.LoginService;
#RunWith(SpringRunner.class)
#SpringBootTest
public class OcpJpaApplicationTests {
#Autowired LoginService loginService;
#Test
public void contextLoads() {
}
}
When I ran this code did show me the folow error.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'loginService': Unsatisfied dependency
expressed through field 'loginDao': No qualifying bean of type
[com.br.suppcomm.ocp.dao.LoginDao] found for dependency
[com.br.suppcomm.ocp.dao.LoginDao]: expected at least 1 bean which
qualifies as autowire candidate for this dependency. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)};
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [com.br.suppcomm.ocp.dao.LoginDao] found for
dependency [com.br.suppcomm.ocp.dao.LoginDao]: expected at least 1
bean which qualifies as autowire candidate for this dependency.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I dont know what happened!! Please.
Add #Repository your Interface
annotation , so that it can be Autowired.
#Repository
public interface LoginDao extends JpaRepository<Login, Long>{
}
It'll work that way!
Exception says that SPring is not able to find a qualifier, to Autowired something you need to sterotype it.
Please add the classes attribute to your #SpringBootTest annotation as follows:
#SpringBootTest(classes = { Application.class })
So that it will know that it has to do component scan, etc that you've specified on your Application class.
Add #Repository annotation on LoginDao
You need to add this annotation to your test:
#DataJpaTest
This will cause the Persistence slice of you application to be initialized.

Resources