I am trying to create some unit tests for my REST API service class. This service class implements a service interface. However, when I try to run my tests I get this error:
org.springFramework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dev.x.y.unit.ContactServiceImplTest': Unsatisfied dependency expressed through field 'contactServiceImpl';
My test class:
#ExtendWith(SpringExtension.class)
class ContactServiceImplTest {
#MockBean
private ContactRepository contactRepository;
#Autowired
private ContactServiceImpl contactServiceImpl;
...
my contactServiceImpl implements from my ContactService, I have tried annotating with #Component and #Service, but I am still receiving the same error.
ContactServiceImpl class:
#Service
#Transactional
public class ContactServiceImpl implements ContactService {
Logger logger = LoggerFactory.getLogger(ContactServiceImpl.class);
#Autowired
private final ContactRepository contactRepository;
....
My interface:
#Service
public interface ContactService { ... }
Any advice would be amazing.
Related
I wonder whether it's possible to replace all the Autowired fields with final ones and #RequiredArgsConstructor below the class declaration?
For instance, replace the following code
public class Controller {
#Autowired
private Reposiroty repository;
#Autowired
private Service service;
...
}
with something like that:
#RequiredArgsConstructor
public class Controller {
private final Reposiroty repository;
private final Service service;
...
}
Thanks in advance!
I have this REST controller:
package com.company.rest;
#RestController
#RequestMapping("/v1/orders")
public class OrderController {
#Autowired
private OrderService orderService;
...
being the OrderService implementation:
package com.company.service.impl;
#Service
public class OrderServiceImpl implements OrderService {
#Autowired
private MessageService messageService;
...
and MessageService implementation:
package com.company.service.impl;
import org.springframework.mail.javamail.JavaMailSender;
#Service
public class MessageServiceImpl implements MessageService {
#Autowired
public JavaMailSender emailSender;
...
This works perfect in development environment, but I have this unit test for the OrderController (based on this tutorial):
package com.company.test;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = AdminApplication.class)
#WebAppConfiguration
public class OrderTest {
private MockMvc mockMvc;
#Autowired
private OrderService orderService;
...
which results in:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Why does this dependency is satisfied in production but not in test? What do I need to do to allow this unit test successfully inject (or mock) a JavaMailSender implementation?
The JavaMailSender bean is not created beacause Spring test runner cannot get required configuration.
For example, there is no spring.mail.host in application.properties.
One of the solution is adding a TestConfiguration for JavaMailSender.
#TestConfiguration
public class TestConfigForMail {
#Bean
public JavaMailSender mailSender() {
final JavaMailSenderImpl sender = new MockMailSender();
return sender;
}
private class MockMailSender extends JavaMailSenderImpl {
#Override
public void send(final MimeMessagePreparator mimeMessagePreparator) throws MailException {
final MimeMessage mimeMessage = createMimeMessage();
try {
mimeMessagePreparator.prepare(mimeMessage);
final String content = (String) mimeMessage.getContent();
final Properties javaMailProperties = getJavaMailProperties();
javaMailProperties.setProperty("mailContent", content);
} catch (final Exception e) {
throw new MailPreparationException(e);
}
}
}
}
Note: The code of MockMailSender is came from Fahd Shariff.
Then import the TestConfiguration to your test case.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = AdminApplication.class)
#Import(TestConfigForMail.class)
#WebAppConfiguration
public class OrderTest {
private MockMvc mockMvc;
#Autowired
private OrderService orderService;
...
I am writing Unit test for one controller and here is my code
public class MyController
{
#Inject
private MyService myService;
public List<Car> getCars()
{
myService.getCars();
}
}
public class MyServiceImpl implements MyService
{
#Inject
AService aService;
#Inject
BService bService;
public List<Car> getCars()
{
aService.getCars();
}
}
Public class MyControllerTest
{
private MockMvc standAloneMockMvc;
#InjectMocks
MyController myController;
#Mock
private MyService myService;
#Before
public void initTestObjs()
{
MockitoAnnotations.initMocks(this);
this.standAloneMockMvc = MockMvcBuilders.standaloneSetup(myController).build();
}
#Test
public void testGetAllCars() throws Exception
{
String url = "/car/list";
List<Car> listCars = new ArrayList<Car>();
Car car = new Car();
listCars.add(car);
Mockito.when(myService.getCars()).thenReturn(listCars);
MvcResult result = standAloneMockMvc.perform(MockMvcRequestBuilders.get(url))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
String jsonResult = result.getResponse().getContentAsString();
}
}
I am facing error in creating bean for myService in MyControllerTest when it tries to load aService and bService.
Can anyone help out on this? Anyone else faced similar issues?
Stacktrace:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.xyz.AService com.xyz.aService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xyz.AService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.inject.Inject()}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
You need to provide exactly all the mock implementation, ie. Your test class is unable to figure out what these AService aService; BService bService; are.
#mock will look all the fields to be presented(mocked)
So, you can provide mock provide mock implementation for them
..
private MockMvc standAloneMockMvc;
#InjectMocks
MyController myController;
#Mock
private MyService myService;
#Mock
AService aService;
#Mock
BService bService;
....
#Component
public class IServiceCollection {
#Resource
private IService service1;
#Resource
private IService service2;
#Resource
private IService service3;
#Resource
private IService service4;
#Resource
private IService service5;
public List<IService> getAllServices(){
List<IService> iServiceList = new ArrayList<IService>();
iServiceList.add(service1);
iServiceList.add(service2);
return iServiceList;
}
}
in IServiceCollection I will refer lots of IService beans like service1, servvice2, etc. I wanna get all of the service beans in method getAllServices().
How can I add all the services to the list automatically, not like the code above?
You have a few options:
.1. If you inject in a map this way:
#Component
public class IServiceCollection {
#Autowired
private Map<String, IService> services;
that would inject in all implementations of IService with the key of the map being the bean name
.2. You can inject in a list this way:
#Component
public class IServiceCollection {
#Autowired
private List<IService> services;
again you would have a list of IService instances.
Is there any way to inject non-mocked objects with #InjectMocks?
My Setup has a UserSignupService with dependencies to a MailService and a UserRepository (a Spring Data Repository). I've a unit test creating a spy of the MailService and I annotated the UserSignupService with #InjectMocks. Sadly this won't inject the UserRepository (non-mocked) into the service class.
Combining #InjectMocks with #Autowired won't inject the mocked MailService, but the bean from the application context.
MockitoAnnotations.initMocks() is run in AbstractServiceTest.setUp(). This class also holds the configuration of the the unit test (SpringJunit4TestRunner, etc.)
public class UserSignupServiceTest extends AbstractServiceTest {
#Autowired #Spy
private MailService<UserActivationMail> mailService;
#InjectMocks
private UserSignupServiceImpl service;
#Before
public void setUp() throws Exception {
super.setUp();
}
}
#Service
public class UserSignupServiceImpl implements UserSignupService {
private final UserRepository repository;
private final MailService<UserActivationMail> mailService;
#Autowired
public UserSignupServiceImpl(UserRepository repository,
MailService<UserActivationMail> mailService) {
this.repository = repository;
this.mailService = mailService;
}
//methods...
}
You need to initialize your Mockito MockitoAnnotations.initMocks(this);
Here is sample Spring JUnit test class I have
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:config/spring-context.xml" })
public class SpringKPTest {
#Autowired
SomeClassA SomeClassA;
#Mock
SomeClassB SomeClassB;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
}