Mockito: injected component returns null - java

I have an issue. I use Mockito Framework to test a service but I have to inject another service into it in order to work. The problem is that I get a NullPonterException when I try to use the second service. Is there a special way to inject the different mock objects into the two services. My code currently looks like this:
#ExtendWith(MockitoExtension.class)
public class Service1Test {
#Mock
Repository1 repository1;
#Mock
Repository2 repository2;
#Mock
Repository3 repository3;
#Mock
Repository4 repository4;
#InjectMocks
Service1 service1;
#InjectMocks
Service2 service2;
}
#Service
public class Service1Impl implements Service1 {
private final Repository1 repository1;
private final Repository2 repository2;
#Autowired
public Service1Impl (Repository1 repository1, Repository2 repository2) {
this.repository1; = repository1;
this.repository2; = repository2;
}
}
#Service
public class Service2Impl implements Service2 {
private final Repository1 repository1;
private final Repository2 repository2;
private final Repository3 repository3;
private final Repository4 repository4;
#Autowired
public PostServiceImpl(PostRepository postRepository, CommentRepository commentRepository, TagRepository tagRepository, CategoryRepository categoryRepository) {
this.postRepository = postRepository;
this.commentRepository = commentRepository;
this.tagRepository = tagRepository;
this.categoryRepository = categoryRepository;
}
}

Related

Cannot instantiate #InjectMocks field named 'userService' of type 'UserServiceImpl'. You haven't provided the instance

I've got a problem with mockito tests named "Cannot instantiate #InjectMocks field named 'userService' of type 'UserServiceImpl'.
You haven't provided the instance at field declaration so I tried to construct the instance." I've been searching through stackoverflow but unfortunately I haven't found right solution for myself.
So, I've got interface 'UserService', its implementation and several methods which I wanna tests.
UserService:
public interface UserService {
Optional<User> getByToken(String token);
PagingDto<User> getUsers(String filter, Integer startIndex, Integer count);}
UserServiceImpl:
public class UserServiceImpl extends AbstractPagingService<User, Integer, UserEntity> implements UserService {
private final UserRepository userRepository;
#Autowired
public UserServiceImpl(ProviderConfiguration providerConfiguration, UserRepository userRepository) {
super(providerConfiguration.getFilter().getMaxResult(), userRepository, Sort.by("surname"));
this.userRepository = userRepository;
}
four methods
Test class:
#ExtendWith(SpringExtension.class)
class UserServiceImplTest {
private static final String TOKEN = "token";
#InjectMocks
private UserServiceImpl userService;
#Spy
private UserRepository userRepository;
#Test
void testGetByToken() {
final UserEntity userEntity = new UserEntity();
final int id = 1;
final User expectedUser = new User();
final String email = "email#email.com";
final String surname = "surname";
final String name = "name";
final String patronymic = "patronymic";
userEntity.setId(id);
expectedUser.setId(id);
expectedUser.setEmail(email);
expectedUser.setSurname(surname);
expectedUser.setName(name);
expectedUser.setPatronymic(patronymic);
when(userRepository.findById(id)).thenReturn(Optional.of(userEntity));
final User actualUser = userService.getByToken(TOKEN).orElseThrow();
assertEquals(expectedUser, actualUser);
assertEquals(email, userEntity.getEmail());
assertEquals(surname, userEntity.getSurname());
assertEquals(name, userEntity.getName());
assertEquals(patronymic, userEntity.getPatronymic());
}
#Test
void testGetAbsentUserByToken() {
assertFalse(userService.getByToken(TOKEN).isPresent());
}
#Test
void testEmptyUser() {
when(userRepository.findById(any())).thenThrow(IllegalArgumentException.class);
assertFalse(userService.getByToken(TOKEN).isPresent());
}
Everything is OK if I didn't extends AbstractPagingService<User, Integer, UserEntity>. But if I do there always be a mistake I mentioned above.
You are missing a mock for ProviderConfiguration which is a required dependency for your service.
#ExtendWith(SpringExtension.class)
class UserServiceImplTest {
private static final String TOKEN = "token";
#InjectMocks
private UserServiceImpl userService;
#Spy
private UserRepository userRepository;
#Mock
private ProviderConfiguration providerConfiguration;
Probably needs some more steps to be properly set up, including mocking getFilter() or by having the mock return mocks (generally discouraged).
If ProviderConfiguration is a data class without much logic, consider assigning a real config in your test:
#ExtendWith(SpringExtension.class)
class UserServiceImplTest {
private static final String TOKEN = "token";
private ProviderConfiguration providerConfiguration = createTestProviderConfiguration();
#InjectMocks
private UserServiceImpl userService;
#Spy
private UserRepository userRepository;
private static ProviderConfiguration createTestProviderConfiguration() {
final Filter filter = new Filter();
filter.setMaxResult(42);
final ProviderConfiguration cfg = new ProviderConfiguration();
cfg.setFilter = filter;
return cfg;
}

How to mock the mongoTemplate Object using Mockito FrameWork?

#RunWith(MockitoJUnitRunner.class)
public class EmailServiceTest {
// #InjectMocks
private EmailService emailService;
#Mock
private JavaMailSender javaMailSender;
#Mock
private MongoTemplate mongoTemplate;
#Mock
private FileStorageProperties fileStorageProperties;
#Mock
private Path fileStorageLocation;
}

Spy dependencies with Mockito

I have a bit of mess with Mockito and fields annotated with #Spy .
I want to test this class:
#Service
public class CategoryServiceImpl implements CategoryService {
#Autowire
private CategoryRepository categoryRepository;
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#Autowired
public void createMapper(final Mapper mapper) {
boundMapper = mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class);
}
// Rest of methods...
}
So, I have created a testing class as shown below:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
#Spy
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
When Mockito instances categoryServiceImpl injects categoryRepository as a mock class but it does not know how to create boundMapper. This class depends on mapper, so I have rewritten my code:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = spy(mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class));
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
But now the problem is the creation of boundMapper is executed before Mockito injects mapper, so I get a NullPointerException.
So, is there any way to create an spy class who depends on another one and finally inject this last one in a field tagged as #InjectMocks?
If you have a spy that depends on a mock or a spy, the only way I've seen to do it is inside the #Before decorated function.
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = ;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
#Before
public void setup() {
boundMapper = spy(mapper
.getMapperFactory()
.getMapperFacade(CategoryDTO.class, Category.class)
);
}
// Rest of methods...
}
I'm not sure how this works with #InjectMocks, so that might be something to look into. There might be a non-decorator version of it that you can run after boundMapper is initialized if CategoryServiceImpl is dependent on it.

How can Mockito mocks be wired when there is no constructor?

I was going through this tutorial which sets up the SUT using a constructor but my question is what if there is no constructor e.g. if we have:
#Autowire private PetRepository petRepository;
#Autowire private VetRepository vetRepository;
#Autowire private OwnerRepository ownerRepository;
#Autowire private VisitRepository visitRepository;
in the service/controller. How we can set this up?
I prefer to annotate the setters instead of the attributes on the classes. For example:
public class SomeClass implements SomeInterface {
private PetRepository petRepository;
private VetRepository vetRepository;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;
... some methods ...
#Resource
public void setPetRepository(PetRepository petRepository) {
this.petRepository= petRepository;
}
#Resource
public void setVetRepository(VetRepository vetRepository) {
this.petRepository= vetRepository;
}
#Resource
public void setOwnerRepository(OwnerRepository ownerRepository) {
this.ownerRepository = ownerRepository;
}
#Resource
public void setVisitRepository(VisitRepository visitRepository) {
this.visitRepository= visitRepository;
}
}
Then you can create a test case like this with Mockito and Junit:
public class SomeClassTestCase {
#Mock
private PetRepository petRepository;
#Mock
private VetRepository vetRepository;
#Mock
private OwnerRepository ownerRepository;
#Mock
private VisitRepository visitRepository;
private SomeClass someClass;
#Before
public void before(){
MockitoAnnotations.initMocks(this);
someClass = new SomeClass();
someClass.setPetRepository(petRepository);
someClass.setVetRepository(vetRepository);
someClass.setOwnerRepository(ownerRepository);
someClass.setVisitRepository(visitRepository);
}
#Test
public void someTest() {
...
}
}
Hope it helps.
You can use Mockito's #InjectMocks annotation. This will instantiate and then inject the Mock dependencies, for example:
#RunWith(MockitoJUnitRunner.class)
public ServiceTest {
#Mock
PetRepository petRepository
// ...omitted mocks ...
#InjectMocks
ClinicServiceImpl service;
}
See the documentation for further usage examples and caveats.

#InjectMocks and non-mocked objects (Spring Data Repositories)

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);
}
}

Categories