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;
....
Related
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.
I have a spring boot test as below
#SpringBootTest(class=AppConfig.class)
Public class AppTest{
#Autowired
private Product product
#Test
Public void test(){
.....
.....
}
}
My AppConfig.class is as below
Public clas AppConfig{
#Mock
EMailService emailService;
public AppConfig(){
MockitoAnnotations.initMocks(this)
}
#Bean
Public Product getProduct(){
return new Product();
}
}
Class Product{
#Autowired
private EMailService emailService
.....
......
}
Even after i defined #Mock EMailService emailService, whem i run the test, I get error EMailService bean not defined.
In your AppTest class
#SpringBootTest(class=AppConfig.class)
public class AppTest{
#Mock
private EMailService emailService;
#InjectMocks
private Product product;
#Test
public void test(){
.....
.....
}
}
Also, I think you do not need the definitions in the AppConfig class anymore
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;
...
Is it possible to just ignore/mock any injected dependencies inside a MockedBean?
Example:
#Service
public class MyService {
#Autowired
private MailerService mailer;
public void test1() {
//does not use mailer
}
public void test2() {
//...
mailer.send();
}
}
#Service
public class MailerService {
//I want these to be automatically mocked without explicit declaration
#Autowired
private JavaMailSender sender;
#Autowired
private SomeMoreService more;
//also these should be mocked without having to provide properties
#Value("${host}") private String host;
#Value("${user}") private String user;
#Value("${pass}") private String pass;
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowird
private MyService myservice;
#MockBean
private MailserService mailer;
#Test
public void test1() {
myservice.test1();
}
}
I could use #MockBean to sort out mailer injection dependency. But any service inside the mocked bean would also have to be explicitly mocked.
Question: is it possible to mock a service "away". Means, just mock the bean and don't care what's inside the #MockedBean (or automatically also mock anything inside #MockedBean)?
As for me the best way to inject mocks is to use MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MocksTests {
#InjectMocks
private ParentService parent;
#Mock
private InnerService inner; // this will be injected into parent
//your tests
}
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);
}
}