I can't autowire Service class in Spring Boot Test - spring-boot

I created Dao Repository that uses jdbc for working with DB.
I autowired this repository in my Service class.
Then I try to autowire my service class in my test class.
#SpringBootTest
public class ServiceTest {
#MockBean
private Dao dao;
#Autowired
private Service service;
#Test
void whenSomething_thanSomething() {
when(Dao.getStatus(anyString())).thenReturn("green");
assertEquals(0, service.getStatus(""));
}
//other tests...
}
#Service
public class Service {
private DaoImpl daoImpl;
#Autowired
public Service(DaoImpl daoImpl) {
this.daoImpl = daoImpl;
}
//...
}
#Repository
public class DaoImpl omplements Dao {
private NamedParameterJdbcOperations jdbc;
#Autowired
public DaoImpl(NamedParametedJdbcOperations jdbc) {
this.jdbc = jdbc;
}
//...
}
When I start test I get the next error:
Parameter 0 of constructor in Service required a bean of type DaoImpl that could not be found.
How can I resolve my problem?

Since you inject DaoImpl in your service-class you were probably intending to mock DaoImpl instead of Dao:
#SpringBootTest
public class ServiceTest {
#MockBean
private DaoImpl daoImpl;
...
}

Related

NPE when not injecting mock data for mapper class (spring boot)

I am using spring boot. I have the below mapper class to map the entity object to model object.
#Mapper(componentModel = "spring")
public interface PersonMapper {
PersonEntity personModelToPersonEntity(PersonModel pm)
PersonModel personEntityToPersonModel(PersonEntity pe)
}
Service class:
#Service
public class MyService{
#Autowired
PersonMapper personMapper;
#Autowired
PersonRepository personRepo;
#Transactional
public List<Person> getDetails() {
List<Person> personList = personRepo.findAll();
List<PersonModel> pm = personMapper.personEntityToPersonModel(personList);
...
...
}
}
I have the below Junit test case, where I'm mocking the data.
#ExtendWith(MockitoExtension.class)
public class PersonTest{
#InjectMocks
PersonService personService;
// #Mock
// PersonMapper personMapper;
#Mock
PersonRepository personRepo;
#Test
void getPersonDetailsTest() {
given(personRepo.findAll()).willReturn(mymockData);
//given(personMapper.personEntityToPersonModel(..).willReturn(..);
...
}
}
Eveything works if I mock the personMapper, but i don't want to mock the mapper class, when test case is executing, as i'm sending the mock entity data using "given(personRepo.findAll()).willReturn(mymockData);" so when it hits the service it should automatically convert the mock data sent to model object. In my case when i have commented the code for mocking mapper class, it is throwing NullPointerException in service class at the mapper object.
As #M. Denium said, nothing is there, because application context isn't raising with MockitoExtension. So, you can either mock your PersonMapper and stub its behavior or inject it manually with ReflectionTestUtils:
#ExtendWith(MockitoExtension.class)
public class PersonTest{
#InjectMocks
PersonService personService;
PersonMapper personMapper = Mappers.getMapper(PersonMapper.class);
#Mock
PersonRepository personRepo;
#Test
void getPersonDetailsTest() {
ReflectionTestUtils.setField(personService, "personMapper", personMapper);
given(personRepo.findAll()).willReturn(mymockData);
...
}
}

Mock bean is autowired into #Spy bean mockito

My unit test try #Spy beanA. But BeanA #autowire bean B as bellow:
#RunWith(SpringRunner.class)
public class MyServiceImplTest {
#Spy
private BeanA beanA;
#InjectMocks
private MyService myService = new MyServiceImpl();
#Test
public void testDoSomeThing(){
myService.doSomeThing();
}
}
MyServiceImpl as bellow :
#Service
public class MyServiceImpl {
#Autowired
private BeanA beanA;
public doSomeThing(){
....
beanA.beanADoSomeThing()
....
}
}
beanA as bellow
#Service
public class BeanA {
#Autowired
private BeanB beanB;
public beanADoSomeThing(){
...
//Null pointer exception in here because beanB=null
beanB.beanBDoSomeThing()
}
}
when run unit test i get null pointer exception at line beanB.beanBDoSomeThing(), I can understand the reason but how to resolve this issue?
I have tried
#Mock
private BeanB beanB;
But this not work, how to resolve this issue ?
If you want to spy your bean in context, you need #SpyBean annotation instead of #Spy and also you should autowire your service to be tested, smth like this:
#SpringBootTest
#RunWith(SpringRunner.class)
public class ExTest {
#SpyBean
private BeanA beanA;
#Autowired
private MyService myService;
#Test
public void testDoSomeThing() {
myService.doSomeThing();
}
}
If you don't want to load application context and test only MyServiceImpl behavior in isolation, you can use pure Mockito and mock or spy dependencies of MyServiceImpl:
#RunWith(MockitoJUnitRunner.class)
public class MockitTest {
#InjectMocks
private MyServiceImpl myService;
#Mock
private BeanA beanA;
#Test(expected = RuntimeException.class)
public void test() {
doThrow(new RuntimeException()).when(beanA).beanADoSomeThing();
myService.doSomeThing();
}
}

#Autowired is not working for CrudRepository

I have problems injecting a repository, there is no problem injecting a Service. Im injecting the repo in a service:
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
and the repository is:
public interface AuthorRepository extends CrudRepository<Author, Integer> {
}
And my code structure is the following:
with the main class:
#SpringBootApplication
public class AuthorBookGraphqlApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorBookGraphqlApplication.class, args);
}
}
the error is thrown on start:
Field repository in com.author.book.graphql.demo.service.AuthorService required a bean of type 'com.author.book.graphql.demo.repository.AuthorRepository' that could not be found.
Update code as below
Spring will automatically import the beans into the container and inject to dependencies with these annotations.
#Component, #Controller, #Service and #Repository - Helps to define the beans so the container is aware of them and can inject them for you with #Autowired.
#Autowired - Handles only wiring part here.
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
#Repository
public interface AuthorRepository extends CrudRepository<Author, Integer> {}
Before class AuthorRepository, Let's put more annotation #Repository.

Unsatisfied dependency during test

I have a spring boot 2.0.0 M2 application who run well.
I use autowired on constructor
#RequestMapping(value = "/rest")
#RestController
public class AddressRestController extends BaseController{
private final AddressService AddressService;
#Autowired
public AddressRestController(final AddressService AddressService) {
this.AddressService = AddressService;
}
...
}
#Service
public class AddressServiceImpl extends BaseService implements AddressService {
#Autowired
public AddressServiceImpl(final AddressRepository AddressRepository) {
this.AddressRepository = AddressRepository;
}
private final AddressRepository AddressRepository;
...
}
public interface AddressRepository extends JpaRepository<Address, Integer>, AddressRepositoryCustom {
}
#Repository
public class AddressRepositoryImpl extends SimpleJpaRepository implements AddressRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Autowired
public AddressRepositoryImpl(EntityManager em) {
super(Address.class, em);
}
...
}
When i try to run a basic test
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
#Autowired
private AddressService service;
#MockBean
private AddressRepository restTemplate;
#Test
public void getAddress(){
MockitoAnnotations.initMocks(this);
Pageable page = PageRequest.of(0, 20);
Page<Address> pageAdr = mock(Page.class);
given(this.restTemplate.findAll(page)).willReturn(pageAdr);
Page<AddressDto> pageDto = service.getAddress(page);
}
}
I get this error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.sonos.arcor.service.AddressServiceTest': Unsatisfied dependency
expressed through field 'service'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type ''com.sonos.arcor.service.AddressService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why i get this error.
You need to annotate the test with SpringBootTest so that spring initialize an application context
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
#SpringBootTest
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
// the remaining test
}
Also you do not need MockitoAnnotations.initMocks(this);
Spring takes care of the mock handling
When [#MockBean is]used on a field, the instance of the created mock will also be
injected. Mock beans are automatically reset after each test method
see Mocking and spying beans

spring autowiring fails but appcontext resolves bean

i have the following issue with spring. I have a webapp and a domain project. the domain project contains a studentService which should be injected through autowiring in a class of the webapp. I've added and to the appcontext.xml.
this is the class from the webapp:
#Component
public class JSONToDomainObjects
{
#Autowired
private StudentService studentService;
private void bindSubmissionValuesToDomainObjects(Integer userKey) throws Exception
{
Student student = studentService.getStudentBySlNumber(userKey);
}
}
then the studentservice:
#Service
public class StudentService
{
..
}
So once I startup my app I see that the studentService is null, but when I get the appcontext and invoke the method getBean("studentService") than a studentservice instance is returned. I use spring 3.0.5. Does anybody have a clue why the autowiring fails?
cheers,
Michael
Why don't you use dependency injection in your testclasses as well? Something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"appcontext.xml"})
public final class JSONToDomainObjectsTests {
private StudentService service;
#Autowired
public void setService(StudentService service) {
this.service= service;
}
#Test
public void testJSONToDomain() {
service.foo();
}
}
Are you using <context:annotation-config/> in your appcontext.xml?

Resources