public class ABCService implements XYZ
{
private final ARepository aRepository;
private final BRepository bRepository;
private final SomeService someService;
public ABCService (ARepository aRepository, BRepository bRepository)
{
this.aRepository= aRepository;
this.bRepository= bRepository;
this.someService= new SomeService (aRepository, bRepository);
}
#Transactional
public void someMethod(Parameters parameter)
{
aRepository.findById(something)
...
someService.doSomething(someParameters);
The test class:
#ExtendWith(MockitoExtension.class)
public class ABCServiceTest
{
#Mock
private ARepository aRepository;
#Mock
private BRepository bRepository;
#Mock
private SomeService someService ;
private ABCService abcService;
#BeforeEach
public void setup()
{
abcService = new ABCService(aRepository, bRepository);
#Test
void someMethodTest()
{
when(aRepository.findById("12345")).thenReturn(null);
abcService.someMethod(parameter);
verify(someService, times(1)).doSomething(any());
}
My error:
Wanted but not invoked:
someService.doSomething(
<any>
);
-> at de.sick.agency.sapmirrorservice.domain.services.SapMirrorServiceTest.onLoiproReceivedTest(SapMirrorServiceTest.java:122)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
someService.doSomething(
<any>
);
-> at packages.ABCServiceTest.someMethodTest(ABCServiceTest.java:122)
Actually, there were zero interactions with this mock.
Related
I have two classes which are annotated as #Component
#Component
public class ClientMapper {
public Client convert(ClientEntity clientEntity) {
Client client = new Client();
BeanUtils.copyProperties(clientEntity, client);
return client;
}
public ClientEntity convert(Client client) {
ClientEntity clientEntity = new ClientEntity();
BeanUtils.copyProperties(client, clientEntity);
return clientEntity;
}
}
#Component
public class OrderMapper {
public Order convert(OrderEntity orderEntity) {
Order order = new Order();
BeanUtils.copyProperties(orderEntity, order);
return order;
}
public OrderEntity convert(Order order) {
OrderEntity orderEntity = new OrderEntity();
BeanUtils.copyProperties(order, orderEntity);
return orderEntity;
}
}
I injected them into different services
#Service
#AllArgsConstructor
public class ClientServiceImpl implements ClientService {
private final ClientMapper clientMapper;
private final ClientRepository clientRepository;
#Service
#AllArgsConstructor
public class OrderServiceImpl implements OrderService {
private final OrderMapper orderMapper;
private final OrderRepository orderRepository;
private final OrderNumberRepository orderNumberRepository;
But all time my mappers is null. I don't create new Object of them using new command. Also with my repository interfaces everything is fine, so my way to inject my comments(#AllArgsContrustor) works correct.
Little note, I have tests classes where I used #InjectMocks on my services classes. Can it be that my error occupied because of this annotation?
#ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
#Mock
private OrderRepository orderRepository;
#InjectMocks
private OrderServiceImpl orderService;
You are using MockitoExtension, spring won't create component of OrderMapper.
If you need actual implementation. Use #Spy annotation of MockitoExtension.
#ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
#Mock
private OrderRepository orderRepository;
#Spy
private OrderMapper orderMapper = new OrderMapper(); // Note: new OrderMapper() is optional as you have No Argument Constructor
#InjectMocks
private OrderServiceImpl orderService;
Or as a practice #Mock is always best way to go instead of #Spy incase of Unit test.
I have service:
#Service
class UserService {
private final Map<AbstractSomeService, CustomEnum> someMap;
public UserService(List<AbstractSomeService> someService) {
someService.forEach(service -> someMap.put(service.getCustomEnum(), service));
}
public void logicExecution() {
//code
}
}
When i am mocking as below: i am getting NullPointer:
#Mock
private SomeService someService; // Service which is extended of AbstractSomeService
#InjectMocks
private UserService userService = new UserService(Collection.singletonList(someService))
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
public void testBrokenJunit() {
userService.logicExecution(); // NULL POINTER HERE (
}
SomeService:
#Service
public class SomeService extends AbstactSomeService() {
public CustomEnum getCustomEnum() {
return CustomEnum.BROKEN_JUNIT_TEST;
}
//logic here
}
Stack trace is quite simple:
java.lang.NullPointerException: Cannot invoke "getCustomEnum()" because "service" is null
StackTrace without constructor initialization:
org.mockito.exceptions.misusing.InjectMocksException:
Cannot instantiate #InjectMocks field named 'UserService' of type '...'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : Cannot invoke "java.util.List.forEach(java.util.function.Consumer)" because "someService" is null
at
Caused by: java.lang.NullPointerException: Cannot invoke "java.util.List.forEach(java.util.function.Consumer)" because "someService" is null
at UserService.<init>
P.S.
When i am using real object of UserService, not a mock everything is ok.
But it doesn't work with #InjectMocks
Try the following in your test class (you don't need to initialize UserService with a new instance via the constructor, #InjectMocks will do that for you):
#Mock
private SomeService someService;
#InjectMocks
private UserService userService;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
public void testBrokenJunit() {
userService.logicExecution();
}
If this does not work because you have a List and not a simple SomeService you can do the following:
#Mock
private SomeService someService;
private UserService userService;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
userService = new UserService(Collection.singletonList(someService));
}
#Test
public void testBrokenJunit() {
userService.logicExecution();
}
Use #MockBean to create mock objects
import org.springframework.boot.test.mock.mockito.MockBean;
#MockBean
private User user;
I have a rest controller which I am trying to Unit Test:
It has a few dependencies autowired
#RestController
#RequestMapping("/test")
public class TestController {
private final Dep1 dep1;
private final Dep2 dep2;
private final Dep3 dep3;
public TestController(final Dep1 dep1,
final Dep2 dep2,
final Dep3 dep3) {
this.dep1 = dep1;
this.dep2 = dep2;
this.dep3 = dep3;
}
}
I recently added dep3
#Service
public class Dep3 {
private final IValidator validator;
public Dep3(final IValidator validator) {
this.validator= validator;
}
public void validate(final Request req) {
validator.validate(req);
}
}
Dep3 has its own Autowired Dependency IValidator
Here is my test class:
#WebMvcTest(TestController.class)
public class TestControllerTest {
#MockBean
private Dep1 dep1;
#MockBean
private Dep2 dep2;
#MockBean
private Dep3 dep3;
#Autowired
private MockMvc mockMvc;
#Test
public void someTest() throws Exception {
}
#TestConfiguration
static class InnerConfiguration {
#Bean
IValidator validator() {
return new SomeValidator();
}
}
}
For my test, I need the code to actually run the dep3.validate(..) with the implementation SomeValidator(). I am unsure how to achieve this. Perhaps I am missing an annotation?
Don't mock Dep3. Instead configure Dep3 bean in #TestConfiguration:
#TestConfiguration
static class InnerConfiguration {
#Bean
Dep3 dep3() {
return new Dep3(validator());
}
#Bean
IValidator validator() {
return new SomeValidator();
}
}
Spring will inject fully configured Dep3 into TestController
You have to configure your Mock correctly.
Something like this:
Mockito.when(dep3.validate(Mockito.any(Request.class))).thenReturn(new SomeValidator());
You can do this in your test method or in the setup method before the actual call.
I'd like to test a service class which has two other service classes like as below using Mockito.
#Service
public class GreetingService {
private final Hello1Service hello1Service;
private final Hello2Service hello2Service;
#Autowired
public GreetingService(Hello1Service hello1Service, Hello2Service hello2Service) {
this.hello1Service = hello1Service;
this.hello2Service = hello2Service;
}
public String greet(int i) {
return hello1Service.hello(i) + " " + hello2Service.hello(i);
}
}
#Service
public class Hello1Service {
public String hello(int i) {
if (i == 0) {
return "Hello1.";
}
return "Hello1 Hello1.";
}
}
#Service
public class Hello2Service {
public String hello(int i) {
if (i == 0) {
return "Hello2.";
}
return "Hello2 Hello2.";
}
}
I know how to mock Hello1Service.class and Hello2Service.class with Mockito like as below.
#RunWith(MockitoJUnitRunner.class)
public class GreetingServiceTest {
#InjectMocks
private GreetingService greetingService;
#Mock
private Hello1Service hello1Service;
#Mock
private Hello2Service hello2Service;
#Test
public void test() {
when(hello1Service.hello(anyInt())).thenReturn("Mock Hello1.");
when(hello2Service.hello(anyInt())).thenReturn("Mock Hello2.");
assertThat(greetingService.greet(0), is("Mock Hello1. Mock Hello2."));
}
}
I'd like to mock Hello1Service.class and inject Hello2Service.class using #Autowired like as below.
I tired to use #SpringBootTest but it did not work.
Is there a better way?
#RunWith(MockitoJUnitRunner.class)
public class GreetingServiceTest {
#InjectMocks
private GreetingService greetingService;
#Mock
private Hello1Service hello1Service;
#Autowired
private Hello2Service hello2Service;
#Test
public void test() {
when(hello1Service.hello(anyInt())).thenReturn("Mock Hello1.");
assertThat(greetingService.greet(0), is("Mock Hello1. Hello2."));
}
}
You want to inject dependency with some functionality to be formed then use #Spy.
You don't to load Spring Container and use #Autowired.
#Spy
private Hello2Service hello2Service=new Hello2Service();
You can read more detail about Mock vs Spy ;
https://dzone.com/articles/mockito-mock-vs-spy-in-spring-boot-tests
You can change with Spy for real object instead of Mock.
Test code will be like this;
#RunWith(MockitoJUnitRunner.class)
public class GreetingServiceTest {
#InjectMocks
private GreetingService greetingService;
#Mock
private Hello1Service hello1Service;
#Spy
private Hello2Service hello2Service;
#Test
public void test() {
when(hello1Service.hello(anyInt())).thenReturn("Mock Hello1.");
assertThat(greetingService.greet(0), is("Mock Hello1. Hello2."));
}
}
I have 3 classes:
public class SomeDAO {
// that method I'd want to catch and change
public void getObj() { ... }
}
public class MainService {
private Service2 service2;
public void doMain() {
service2.doSomethingAnother();
}
}
public class Service2 {
private SomeDAO someDAO
public void doSomethingAnother() {
someDAO.getObj();
}
}
All I need - to call doMain but with custom someDao.getObj() inside service2.doSomethingAnother():
public TestClass {
#InjectMocks
private final MainService mainService = new MainService();
#InjectMocks
private final Service2 service2 = new Service2();
#Mock
private SomeDAO someDao;
#Test
public void testMe() {
// substitution
when(someDao.getObj()).thenReturn(new MyObj());
// then I'm calling the outer method
mainService.doMain();
}
}
When running that test I have NPE in mainService.doMain(): service2 in null..
Inside of testMe object service2 is alive and not null, it has been declared as class variable and initialized.
Whether I misundersood #InjectMock behaviour?
Service2 is not injected into MainService, since it is not a mock. Therefore, the server2 attribute of your mainService object is null.
You are also trying to mock too deep. The correct way to test MainService is to mock the dependency of Service2 and not SomeDAO.
A separate test class for Service2 is better where you mock the dependency of SomeDAO.
public TestClass {
#InjectMocks
private MainService mainService;
#Mock
private Service2 service2;
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testMe() {
mainService.doMain();
verify(service2).doSomethingAnother();
}
}