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

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());
}
}

Related

How to use #Autowired in SpringBoot unit test

I am trying to unit test (using JUnit5 jupiter) a class developed in Java with Spring Boot that I would like to use the #Autowired annotation for convenience.
A very simplified version of it is as follow:
import org.springframework.stereotype.Component;
#Component
public class Demo {
public String get() {
return "hello";
}
}
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
#SpringJUnitConfig
class DemoTest {
#Autowired private Demo sut;
#Test
void Test() {
Assertions.assertEquals("hello", sut.get());
}
}
When I run the test this error occurs:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.DemoTest': Unsatisfied dependency expressed through field 'sut'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.Demo' 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.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:417)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
...
How to prevent it?
To be noted: for this test, I do not want to start the full application using #SpringBootTest
Thanks,
Usually when you use #ContextConfiguration (which is a significant part of the stereotype #SpringJUnitConfig annotation) you should specify the configuration class from which the "Demo" component will be resolved.
Otherwise spring won't know which classes to load.
So you should basically create a configuration class (annotated with #Configuration) And specify what do you want to load there, for example with #ComponentScan
Haven't tested it but something like this should work:
#SpringJUnitConfig(MyTestConfig.class)
public class MyTest {
#Autowired Demo sut;
public void test() {... sut.doSomething(...); ...}
}
#Configuration
#ComponentScan(...) // here you should specify how to
// load the Demo class and maybe other classes as well
public class MyTestConfig {
}
Of course if instead of #Component you already use Java Config and define Demo class there you won't need to create this auxiliary MyTestConfig class and can load the configuration with the Demo class right away

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.

Injecting Spring Data Repositories in Junit 5 Tests

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() {
}
}

Spring Actuator - How to exclude HealthEndpoint from autowiring in test

I am trying to run a test but I got an exception when I try to run it Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.actuate.endpoint.HealthEndpoint' available:
I have two packages com.test.data and com.test.health in my main folder. My main Application class is in com.test.data. In com.test.health I have one class with name StartupHousekeeper implements ApplicationListener<ApplicationReadyEvent> and autowired HealthEndpoint there as below
#Component
public class StartupHousekeeper implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
private HealthEndpoint healthEndpoint;
}
In test I have ControllerIntegrationTest which is config class and code is below. Even though I did not add com.test.health package it is still throwing NoSuchBeanDefinitionException.
#Profile("controller-integration-test")
#ComponentScan(basePackages = {"com.test.data"})
#Configuration
public class ControllerIntegrationTest {
}
My actual test class is below
#TestExecutionListeners(MockitoTestExecutionListener.class)
#ActiveProfiles({"controller-integration-test"})
#ContextConfiguration(classes = ControllerIntegrationTest.class)
#WebMvcTest(value = AdminUserController.class, secure = false, excludeAutoConfiguration = {HealthIndicatorAutoConfiguration.class, HibernateJpaAutoConfiguration.class, FlywayAutoConfiguration.class, DataSourceAutoConfiguration.class})
public class AdminUserControllerTest extends AbstractTestNGSpringContextTests implements TestConstants {}
When I try to run it org.springframework.test.context.testng.AbstractTestNGSpringContextTests#springTestContextPrepareTestInstance failed to run due to above mentioned exception

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