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