Here I am trying to mock autowire fields ServiceHelper of Service class TestServiceImpl , I am not able to call method through mock object of ServiceHelper class.
This is my class files:
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestDAO testDAO;
#Autowired
private ServiceHelper serviceHelper;
#Override
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
return serviceHelper.getResults(map);
}
2nd Class:
#Repository
public class ServiceHelper {
private static Logger logger = Logger.getLogger(ServiceHelper.class.getName());
#Autowired
ResponseHeader responseHeader;
public void setResponseHeader(ResponseHeader responseHeader) {
this.responseHeader = responseHeader;
}
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
....
}
And Test class:
#RunWith(MockitoJUnitRunner.class)
public class MockitoTester {
#InjectMocks
private TestServiceImpl serviceImpl = new TestServiceImpl();
#Mock
private TestDAO testDAO;
#Mock
private ServiceHelper sHelper;
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testResult() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("TestId", "test123");
map.put("lang", "en");
map.put("cntry", "USA");
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
Assert.assertEquals(results.getStatus(), "Success");
}
Here in my test class:
results = serviceImpl.getResults(map);
It goes to TestServiceImpl class to method :
public ResultsModel getResults(Map<String, Object> map) throws webServiceException_Exception {
return serviceHelper.getResults(map);
}
but at point :
serviceHelper.getResults(map);
it is not going inside serviceHelper.getResults(map) and return all values as Null.
Please suggest where I need to do changes.
You have three choices here:
Do actual Spring autowiring in your tests
Use injection methods that can legitimately be performed by your tests (constructor parameters, public setters, public fields - in order of preference)
Use reflection to inject your mocks
Option 1 is really integration testing -- you can annotate your test class with #RunWith(SpringRunner.class) and use more Spring annotations to control dependency injection. It's too big a subject to cover in a SO answer, but there are plenty of examples if you Google for "spring integration test mockito".
But for unit testing, I think it's better not to involve Spring. A good Spring bean doesn't need Spring to function. Option 2 just says, write your class so that unit tests (and anything else) can inject the dependency (be it a mock, or anything else) through normal Java means.
Constructor injection is cleanest in my opinion:
private final ServiceHelper serviceHelper; // note: not annotated
#Autowired
public TestService(ServiceHelper serviceHelper) {
this.serviceHelper = serviceHelper;
}
But you can also do this with a public void setServiceHelper(ServiceHelper helper) -- this is less good because the field can't be final.
Or by making the field public -- I assume you know the reasons this is bad.
If you're determined to have a private field that's not set by a public constructor or setter, you could use Spring's ReflectionUtils.setField() from within your test:
#Mock
private ServiceHelper serviceHelper;
private TestService service;
#Before
public void configureService() {
service = new TestService();
Field field = ReflectionUtils.findField(TestService.class, "serviceHelper");
ReflectionUtils.setField(field, service, serviceHelper);
}
(Or, equally, use JDK's reflection classes directly, or reflection utils from elsewhere)
This is explicitly using reflection to subvert the access rules you've coded into the class. I thoroughly recommend option 2.
I think the issue may be that you are stubbing your method to return the same object which you then assign the result of the method under test. i.e. (the results object here):
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
This will probably cause some sort of cyclic confusion when it tries to stub the method in Mockito, and it certainly won't make your assertation pass:
Assert.assertEquals(results.getStatus(), "Success");
Since the status on results is never set anywhere.
I think you need to make separate objects for your stubbing and your returned value from the method under test and make sure you set your stubbed one to have a status of "Success":
ResultsModel results = new ResultsModel();
results.setStatus("Success");
when(sHelper.getResults(map)).thenReturn(results);
ResultsModel returnedResults = serviceImpl.getResults(map);
Assert.assertEquals(returnedResults.getStatus(), "Success");
Try using constructor injection it'd be easier to mock the classes for testing... here's an example on how I would structure my classes to get you going. When you write your tests you now have to pass the Mocked object into the instance you're creating of these classes:
#Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
private ServiceHelper serviceHelper;
#Autowired
public TestServiceImpl(TestDAO testDAO, ServiceHelper serviceHelper) {
this.testDAO = testDAO;
this.serviceHelper = serviceHelper;
}
}
#Repository
public class ServiceHelper {
private ResponseHeader responseHeader;
#Autowired
public ServiceHelper(ResponseHeader responseHeader) {
this.responseHeader = responseHeader
}
}
Related
I'm using spring boot rest API and want to test my service layer. In my service I have autowired few beans and its not through constructor. (I like it that way to keep it short).
In the junit, I have created mocks and for private field which I do want to execute, I have assigned using ReflectionTestUtils.setField. When I debug, the method inside the field is not getting executed which assigned by bean.
Service Class
#Component
public class MyService {
#Autowired
private MyRepository myRepository;
#Autowired
private ResponseMapper responseMapper;
public List<MyObj> getList(String param) throws MyException {
log.info("Getting details");
Optional<List<MyObj>> list = myRepository.findByParam(param);
List<MyObj> data = responseMapper.mapToResponseData(list);
return data;
}
}
Test Class
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
#InjectMocks
private MyService myService;
#Mock
private MyRepository myRepository;
#Mock
private ResponseMapper responseMapper;
#Before
public void setUp() {
ReflectionTestUtils.setField(myService, "responseMapper", responseMapper);
}
#Test
public void getListTest() throws Exception {
when(myRepository.findByParam(anyString()))
.thenReturn(Optional.of(getSampleList()));
List<MyObj> list = myService.getList("param");
assertTrue(list.size() >0);
}
}
This results in Assertion failure and when I debug, the method mapToResponseData in ResponseMapper is not getting executed.
I know I can mock mapToResponseData method also. But I wanted it to execute so I don't have to write another test class for mapper alone.
What am I doing wrong? Is this the right wat to inject bean? And is using constructor in service to inject beans only option?
I have the following code, and I was wondering how to mock the component used in the value annotation. It is not instantiated in the model class, so I can't really use the annotation #InjectMocks, how do I perform a mock in this context?
public interface Vehicule {
#Value('#{target.VEHICULE_ID}')
BigInteger getId();
#Value('#{#mapperUtility.clobToString(target.CERTIFICATE)}') // How to mock this call?
String getCertificate();
}
#Component
public class MapperUtility {
public String clobToString(Clob clob) {
return (clob == null) ? null : ClobType.INSTANCE.toString(clob); // from org.hibernate.type
}
}
public interface VehiculeRepository extends JpaRepository<Vehicule, String> {
#Query(value = SQL_QUERY_FIND_VEHICULE_BY_IDS)
List<Vehicule> findVehiculeByIds(#Param("Ids") List<BigInteger> ids);
}
What would a test that mocks the component inside the value annotation would look like?
This is a pretty common issue when using direct field injection. We solved this problem by writing a Junit5 extension: http://github.com/exabrial/mockito-object-injection
This allows you to cleanly inject data into private members of a class under test, without resorting to fire up an entire container for an integration test.
Example:
#TestInstance(Lifecycle.PER_CLASS)
#ExtendWith({ MockitoExtension.class, InjectExtension.class })
class MyControllerTest {
#InjectMocks
private MyController myController;
#Mock
private Logger log;
#Mock
private Authenticator auther;
#InjectionSource
private Boolean securityEnabled;
#Test
void testDoSomething_secEnabled() throws Exception {
securityEnabled = Boolean.TRUE;
myController.doSomething();
// wahoo no NPE! Test the "if then" half of the branch
}
My ServiceImpl looks like this:
#Service
public class GuildUsersServiceImpl implements GuildUsersService {
#Autowired
private final GuildUsersRepository guildUsersRepository;
#Autowired
private GuildService guildService;
#Autowired
private UserService userService;
#Autowired
private GuildUserRoleTypeService guildUserRoleTypeService;
#Autowired
public GuildUsersServiceImpl(final GuildUsersRepository guildUsersRepository) {
this.guildUsersRepository = guildUsersRepository;
}
public GuildUsers create(GuildUsers guildUser) {
return this.guildUsersRepository.save(guildUser);
}
}
And my service test for create looks like this:
#RunWith(SpringRunner.class)
public class GuildUsersServiceTest {
#Mock private GuildUsersRepository guildUsersRepository;
#Mock private UserService userService;
#Mock private GuildService guildService;
#Mock private GuildUserRoleTypeService guildUserRoleTypeService;
#InjectMocks private GuildUsersServiceImpl guildUsersService;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void createTest() {
GuildUsers guildUsers = mockGuildUsers();
when(guildUsersRepository.save(guildUsers)).thenReturn(guildUsers);
GuildUsers dbGuildUsers = guildUsersService.create(guildUsers);
assertEquals(dbGuildUsers.getId(),guildUsers.getId());
}
}
I am using jUnit4. Despite using when(guildUsersRepository.save(guildUsers)).thenReturn(guildUsers); in the test, I run into a Null Pointer Exception with the following trace:
java.lang.NullPointerException: Cannot invoke "com.project.entities.domain.GuildUsers.getId()" because "dbGuildUsers" is null
I suspect something is wrong with how I have mocked the #Autowired classes. What needs to be done differently while mocking classes in the Test class ?
At the same time I want the services in the following test case to work as well :
#Test
public void createTest1() {
GuildUsers guildUsers = mockGuildUsers();
GuildUsersWithoutGuildIdRequestDTO guildUsersWithoutGuildIdRequestDTO = new GuildUsersWithoutGuildIdRequestDTO();
guildUsersWithoutGuildIdRequestDTO.setUserId(guildUsers.getUser().getId());
guildUsersWithoutGuildIdRequestDTO.setGuildUserRoleTypeId(guildUsers.getGuildUserRoleType().getId());
when(guildService.get(guildUsers.getGuild().getId())).thenReturn(Optional.of(guildUsers.getGuild()));
when(guildRepository.findById(any())).thenReturn(Optional.of(guildUsers.getGuild()));
when(userService.get(guildUsers.getUser().getId())).thenReturn(Optional.of(guildUsers.getUser()));
when(guildUsersRepository.findById(guildUsers.getId())).thenReturn(null);
when(guildUserRoleTypeService.get(guildUsers.getGuildUserRoleType().getId())).thenReturn(Optional.of(guildUsers.getGuildUserRoleType()));
when(guildUsersRepository.save(any())).thenReturn(guildUsers);
GuildUsersResponseDTO dbGuildUsersResponseDTO =
guildUsersService.create(guildUsers.getGuild().getId(),guildUsersWithoutGuildIdRequestDTO);
assertEquals(dbGuildUsersResponseDTO.getGuildUserRoleType(),guildUsers.getGuildUserRoleType());
}
I don't know why you did field injection as well as constructor injection at the same time. You should remove one of them first, for instance:
#Service
public class GuildUsersServiceImpl implements GuildUsersService {
//#Autowired - removed
private final GuildUsersRepository guildUsersRepository;
#Autowired
private GuildService guildService;
#Autowired
private UserService userService;
#Autowired
private GuildUserRoleTypeService guildUserRoleTypeService;
//#Autowired - removed
public GuildUsersServiceImpl(final GuildUsersRepository guildUsersRepository) {
this.guildUsersRepository = guildUsersRepository;
}
public GuildUsers create(GuildUsers guildUser) {
return this.guildUsersRepository.save(guildUser);
}
}
OR remove the constructor to add:
#Autowired
private final GuildUsersRepository guildUsersRepository;```
InjectMock documentation clearly says: "Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below."
In your case, it apparently chooses property injection, hence guildUserRoleTypeService remains uninitialised. Mixing property and constructor injection is not a good idea as pointed above.
To improve the general design and testability of your GuildUsersServiceImpl, I would suggest to stick with constructor injection. This way you can:
a) Declare all the fields as private final, so they will always be set once the object is created, avoiding race conditions and NPEs.
b) Initialise GuildUsersServiceImpl in the test using a proper constructor rather than InjectMocks.
Leaving this here for other people that also wasted an afternoon on trying to get a repository to return what they configured. What ended up being the thing I had to do is rather than annotating the repository with #Mock I had to use the #MockBean annotation for the Mockito/Spring combination to work properly.
As per javadoc of #MockBean:
When #MockBean is used on a field, as well as being registered in the application context, the mock will also be injected into the field.
I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.
I have a class ManageUser as below:
public class ManageUser {
private static UserBO gUserBO = new UserBO();
public String method1() {
gUserBO.callSomeFunction();
gUserBO.callSomeOtherFunction();
}
}
Now, I have a test class where I want to test method1() and since the methods callSomeFunction() and callSomeOtherFunction() end up making database calls I want to mock the calls to those methods. I am unable to do that by using mock since the object in ManageUser is static. How do I proceed? I am new to Junit and Mockito and can't seem to find relevant answers.
Try using Power Mockito:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ManageUser.class})
public class ClassInTest {
#Test
public void testStatic() {
ManageUser mUser = new ManageUser();
Field field = PowerMockito.field(ManageUser.class, "gUserBO");
field.set(ManageUser.class, mock(UserBO.class));
...
}
}
You are "unable to do that by using mock" because your class is badly designed. As a workaround, you could use PowerMock (as #S.K. suggested) to mock the static field but that will only suppress the real problem of your class.
Better take the chance and improve the code for better testability and evolvability:
Step 1: Create an interface for your class UserBO and let it implement it.
public interface UserService {
void callSomeFunction();
void callSomeOtherFunction();
}
public class UserBO implements UserService { ... }
Step 2: Change your class ManageUser to get any implementation of UserService through a constructor.
public class ManageUser {
private final UserService userService;
public ManageUser(UserService userService) {
this.userService = userService;
}
public String method1() {
userService.callSomeFunction();
userService.callSomeOtherFunction();
}
}
Step 3: Change the calling side of your class ManageUser to provide a UserService.
So instead of
ManageUser manager = new ManageUser();
use
ManageUser manager = new ManageUser(new UserBO());
Step 4: Now you can easily mock a UserService in your test and construct a ManageUser with the mock.
This design also enables DI frameworks (e.g. Spring) to inject (or autowire) the components.