Java/Spring-boot/Mockito #MockBean annotation work strange - java

In tests i mock DateService to have the same date every time when i run the test, but when i use DateServie in other service then the mock retun null all the time. It is strange because the mock works in my custom date time provder. Here is the code:
Its work here:
#Service(MyDateTimeProvider.MY_DATE_TIME_PROVIDER)
public class MyDateTimeProvider implements DateTimeProvider {
public static final String MY_DATE_TIME_PROVIDER = "MyDateTimeProvider";
#Autowired
private DateService dateService;
#Override
public Optional<TemporalAccessor> getNow() {
return Optional.of(dateService.getCurrentDate().toInstant());
}
}
#Service
public class DateService {
public Date getCurrentDate() {
return new Date();
}
}
Its not work in the UserService:
#SpringBootTest
public class Test{
#MockBean
protected DateService dateService;
#BeforeEach
public void beforeEach() { Mockito.when(dateService.getCurrentDate()).thenReturn(DEFAULT_DATE_TIME.toDate());
}
...
}
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private DateService dateService;
private User createNewUser(final UserDto dto) {
User user = new User();
user.setEmail(dto.getEmail());
user.setRegistrationDate(dateService.getCurrentDate()); // i got null here
return userRepository.save(user);
}
}
What did i wrong? Thank you!

My colleague helped me. My problem was: i used "UserService" in a method with #PostConstuct annotation, so its run before the mock happened.

Related

I have a question while writing the test code. feat JUnit

#RequiredArgsConstructor
#Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
#Transactional
#Override
public Long insertUser(UserSaveRequestDto userSaveRequestDto) {
Long user_id = userMapper.insertUser(userSaveRequestDto);
return user_id;
}
}
I'm trying to test the service layer.
I wonder which one should be further verified.
The code below simply verified whether the userMapper's insertUser was called or if the parameters were properly contained, what additional verification should be made?
#ExtendWith(MockitoExtension.class)
public class UserServiceTest {
#Mock
UserMapper userMapper;
#InjectMocks
UserServiceImpl userService;
UserSaveRequestDto userSaveRequestDto;
UserResponseDto userResponseDto;
#BeforeEach
void setUp() {
userSaveRequestDto = UserSaveRequestDto.builder()
.userName("test")
.userPhoneNumber("01026137832")
.build();
userResponseDto = UserResponseDto.builder()
.userId(1L)
.userName("test")
.userPhoneNumber("01026137832")
.build();
}
// Mockito 이용한 테스트 코드
#DisplayName("Mock을 사용한 insertUser 테스트")
#Test
public void insertUser() {
// given
// when
Long userId = userService.insertUser(userSaveRequestDto);
// then
ArgumentCaptor<UserSaveRequestDto> captor = ArgumentCaptor.forClass(UserSaveRequestDto.class);
then(userMapper).should().insertUser(captor.capture());
assertThat(captor.getValue()).isEqualTo(userSaveRequestDto);
}
}
You should test if the returned userId has the expected value. Tell the userMapper mock to return a specific value and assert that the userService returned it as well.
assertThat(userId).isEqualTo(expectedIdValue);

How to use #Inject?

Earlier i had the implemenation like:
public class FeedbackService {
private final FeedbackHelper feedbackHelper;
#Inject
public FeedbackService(FeedbackHelper feedbackHelper) {
this.feedbackHelper = feedbackHelper;
}
//rest of the class
}
Test file
public class FeedbackDataServiceTest {
private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.feedbackService = new FeedbackService(feedbackHelper);
}
}
It was workign fine. But when I changed to:
public class FeedbackService {
#Inject private FeedbackHelper feedbackHelper;
}
Test file
public class FeedbackDataServiceTest {
private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
}
The test cases started failing. Is anything else required to be done?
Use #InjectMocks to inject the mocks into the Service class.
public class FeedbackDataServiceTest {
#InjectMocks private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
}
There are three types of injection. The suggestion is to use constructor injection if the dependency is mandatory and setter injection if it is optional.
You can use #InjectMock on the under test object if you want to mock a field injection. But it is hard to test if you want to test without mocking framework.
#RunWith(MockitoJUnitRunner.class)
public class ApplicationTest
{
#InjectMocks
MainClass sut;
#Mock
DatabaseDAO dependentClassOne;
#Test
public void validateTest()
{
boolean saved = sut.save("abcd");
assertEquals(true, saved);
}

How to mock any services inside a #MockedBean?

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
}

Mocked object not getting in my service?

Mocked object not getting in service Here is my below code
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classesExternalProviderMain.class)
#ActiveProfiles(ApplicationConstants.DEVELOPMENT_PROFILE)
#WebAppConfiguration
public class EmployeeServiceTest {
#InjectMocks
EmployeeService employeeService;
#Mock
EmployeeRepository employeeRepository;
String name;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testEmployee() {
Mockito.when(employeeRepository.findByName(name)).thenReturn(getEmployee());
List<Employee> resultedEmployees = employeeService.getEmployeeByName("mike");
}
private List<Employee> getEmployee(){
//here is the logic to return List<Employees>
}
}
public EmployeeServiceImpl implements EmployeeService{
#Autowired
EmployeeRepository employeeRepository;
employeeService.
public List<Employee> getEmployeeByName(String name){
List<Employee> employees = employeeRepository.findByName(name);
//Here I does't want to hit the real database so I have mocked it in testcase but I am getting empty list when I debug it. So can you please tell me what i did wrong in my "EmployeeServiceTest" to get List<Employee>
}
}
So is there any additional logic required in testcase to get the mocked object.
The problem is you are not mocking the call
employeeRepository.findByName("mike")
but you are mocking
employeeRepository.findByName(null)
since your variable name was never initialized. Change your code to:
Mockito.when(employeeRepository.findByName("mike")).thenReturn(getEmployee());

Mock objects returns null

I have below Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringTestConfig.class)
public class UserServiceTest {
#Inject
private UserRepository userRepository;
#Inject
private UserService userService;
#Test
public void testProcessInvoice() throws SQLException {
User user = new User();
user.setFirstName("abc");
when(userRepository.save(any(User.class))).thenReturn(user);
Assert.assertNotNull(userService);
User savedUser = userService.save(user);
Assert.assertEquals("abc", savedUser.getFirstName());
}
}
I have below SpringTestConfig.java
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return Mockito.mock(UserService.class);
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
call to User savedUser = userService.save(user); returns null user object. I am not able to figure it out why it is returning null.
EDIT:
UserRepository is JpaRepository, if this is a problem
public interface UserRepository extends JpaRepository<User, Long> {
}
Your UserService is a mock object, and has no defined behavior for dealing with the #save(User) method.
Mocking the object under test is probably not what you are after here. I would recommend your objects under test are instantiated in the test, and injected with the mocks or stubs of the objects that they utilize.
Your configuration needs to return a real UserService:
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return new UserServiceImpl(); // or whatever your implementation is
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
Mocks are for collaborators, not for the thing you're testing.

Categories