When I try to run the following test
public class FavoriteServiceTest extends AbstractCoreTest {
#Autowired
private FavoriteRepository favoriteRepository;
#Autowired
private RevisionService revisionService;
#Autowired
private FavoriteService favoriteService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(revisionService.getGlobalRevisionNumber()).thenReturn(1L);
}
#Test
public void loadFavorites() throws Exception {
when(favoriteRepository.findFavoritesByUserId("123")).thenReturn(Collections.emptyList());
List<Favorite> favorites = favoriteService.loadFavorites(123L);
assertThat(favorites.size(), is(0));
}
I get the following exception, but im pretty sure the mock is correct initialized
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods
declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at FavoriteServiceTest.setUp(FavoriteServiceTest.java:44) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
Just replace #Autowired with #Mock -.-
#Mock
private DocumentService documentService;
Your favoriteRepository should be a mock object, benfinit from spring boot, you can using #MockBean here.
Related
UserMapper.java
#Mapper
public interface UserMapper {
public List<UserResponseDto> selectUserList();
public void insertUser(UserSaveRequestDto userSaveRequestDto);
}
UserServiceImpl.java
#RequiredArgsConstructor
#Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
#Transactional
#Override
public Long insertUser(UserSaveRequestDto userSaveRequestDto) {
userMapper.insertUser(userSaveRequestDto);
return userSaveRequestDto.getUserId();
}
}
UserServiceTest.java
#ExtendWith(SpringExtension.class)
public class UserServiceTest {
#Mock
UserMapper userMapper;
#InjectMocks
UserServiceImpl userService;
// Mockito 이용한 테스트 코드
#DisplayName("Mock을 사용한 insertUser 테스트")
#Test
public void insertUser() {
// given
UserSaveRequestDto userSaveRequestDto = UserSaveRequestDto.builder()
.userName("test")
.userPhoneNumber("01026137832")
.build();
willDoNothing().given(userMapper).insertUser(userSaveRequestDto);
given(userService.insertUser(userSaveRequestDto)).willReturn(1L);
// when
Long userId = userService.insertUser(userSaveRequestDto);
// then
//mockito 스타일
verify(userMapper).insertUser(userSaveRequestDto);
//BDDMockito 스타일
then(userMapper).should().insertUser(userSaveRequestDto);
assertThat(userId).isEqualTo(1L);
}
}
Exception
org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue:
'insertUser' is a void method and it cannot be stubbed with a
return value! Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod(); If you need to set the void method to do nothing you can use:
doNothing().when(mock).someVoidMethod(); For more information, check out the javadocs for Mockito.doNothing().
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
The method you are trying to stub is overloaded. Make sure you are calling the right overloaded version.
Somewhere in your test you are stubbing final methods. Sorry, Mockito does not verify/stub final methods.
A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
Mocking methods declared on non-public parent classes is not supported.
at com.example.mybatis.user.UserServiceTest.insertUser(UserServiceTest.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
I don't know why the test fails, please help me
I am not sure if I am testing a void returning method the correct way and also if my class-under-test (cut) requires any change in order to make it 100% testable and bug-proof.
I am seeing NullPointerException while executing the test because loginOperations is not getting set.
Error:
java.lang.NullPointerException
at com.demo.service.LoginService.doLogin(LoginService.java:40)
at com.demo.service.LoginServiceTest.doLogin(LoginServiceTest.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
LoginService.java
#Service
public class LoginService {
#Autowired
private ILoginOperations loginOperations;
public void doLogin(HttpServletRequest request, String result) {
LoginDTO loginDTO = new LoginDTO(request.getParameter("username"), result);
loginOperations.doLogin(loginDTO);
}
}
LoginServiceTest.java
public class LoginServiceTest {
private LoginService instance = new LoginService();
ILoginOperations loginOperations = Mockito.mock(ILoginOperations.class);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
String result = "some string";
#Test
public void doLogin() {
when(request.getParameter("username")).thenReturn("johndoe");
instance.doLogin(request, result); //throws NPE while calling loginOperations.doLogin() because
assertNotNull(instance); //IS THIS THE CORRECT WAY TO TEST A VOID RETURNING METHOD ???
}
}
Now, there are 2 ways to fix the test.
I can fix the class-under-test by adding a setter method for loginOperations class and call that setter method in the test
Change #Test public void doLogin() { to #Test(expected = Exception.class) public void doLogin() {
Not sure which one is the best practice above and why.
Another Question:
Other question that I have is how to assert on a method that returns nothing. There is something like verify() but not sure how to use it.
1.You can fix the test case by adding setter method in LoginService or you can use constructor injection like -
#Autowired
public LoginService(ILoginOperations loginOperations) {
this.loginOperations = loginOperations;
}
Validating exception as #Test(expected = Exception.class) public void doLogin() is certainly not a good idea as doLogin method does not throw exception in normal circumstance.
The better way to test method with void return type is using verification API (example - mockito verification API example). You can also use Mockito's ArgumentCaptor to capture argument and assert state of that argument, along with verification API as -
#RunWith(MockitoJUnitRunner.class)
public class LoginServiceTest {
#Captor
private ArgumentCaptor<LoginDTO> captor;
#Mock
private ILoginOperations loginOperations;
#Mock
private HttpServletRequest mockServletRequest;
#InjectMocks
private LoginService loginService;
#Test
public void validateLogin() {
when(mockServletRequest.getParameter("username")).thenReturn("mock_user_name");
loginService.doLogin(mockServletRequest, "mock_result");
verify(loginOperations).doLogin(captor.capture());
LoginDTO expectedLoginDTO = captor.getValue();
assertThat(expectedLoginDTO.getResult(), is("mock_result"));
assertThat(expectedLoginDTO.getUsername(), is("mock_user_name"));
}
}
There is an excellent article from Martin Fowler about this method of testing - Mocks Aren't Stubs
actually you should create a constructor for your LoginService that gets the ILoginOperations, in this way you can create the LoginService in your test class and pass the mocked ILoginOperations as parameter, all this stuff should be done in a #Before method.
Or you can try with #InjectMocks for your LoginService and have your ILoginOperations annotated as #Mock.
I've below void method which I am looking to get mock of.
public void updateEmployee(EmployeeDto dto) {
Employee d = convertToEntity(dto);
employeeRepository.updateEmployee(d.getEmployeeName(), d.getEmployeeDescription(),
d.getEmployeeOwnerEmployeeId(), d.getEmployeeCode(), d.getStatus());
}
But I am getting below error.
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
at com.xxx.EmployeeServiceTest.test_UpdateEmployee(EmployeeServiceTest.java:120)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Test method
#RunWith(PowerMockRunner.class)
#PrepareForTest({StatusEnum.class})
public class EmployeeServiceTest {
#Mock
private Employee employeeMock;
#InjectMocks
private EmployeeServiceImpl employeeServiceImpl;
#Mock
private EmployeeRepository employeeRepositoryMock;
#Mock
private EmployeeDto employeeDtoMock;
#Mock
private StatusEnum statusEnum;
#Mock
private Exception ex;
List<String> employeeNames = new ArrayList<>();
#Before
public void setup() {
// To mock static methods or class
mockStatic(StatusEnum.class);
}
#Test
public void test_UpdateEmployee() {
doNothing().when(employeeServiceImpl).saveEmployee(any(EmployeeDto.class));
employeeServiceImpl.updateEmployee(employeeDtoMock);
/*doAnswer((i) -> {
System.out.println("Employee setName Argument = " + i.getArgument(0));
assertTrue("Pankaj".equals(i.getArgument(0)));
return null;
}).when(employeeServiceImpl).updateEmployee(employeeDtoMock);*/
}
}
The exception here seem clear to me, employeeServiceImpl seems not to be a mock.
How did you instantiate it ? Using Mockito.mock or #Mock on the field ?
--- Edit
To clarify my answer, in the #Before (or equivalent in your test class) instantiate your service with mockito :
this.employeeService = Mockito.mock(EmployeeService.class);
or
#Mock
private EmployeeService employeeService;
And then it should work.
--- Edit
So seeing how you inject your mock I think I might get what's happening.
In fact #InjectMocks does not make your EmployeeService a mock. It allows mockito to know let your framework create the bean and injects the mocks you have created in it.
Here if you have declared your repository as a mock like this
#Mock
private EmployeeRepository employeeRepository;
Then a mock of type EmployeeRepository will be injected inside the employeeService instance, which is not a mock.
Then if it is in fact the repository you want to mock, you should put it in the when in your tests like :
doNothing().when(employeeRepository).saveEmployee(any(EmployeeDto.class));
employeeServiceImpl.saveEmployee(employeeDtoMock);
Then calling your service will go into your service saveEmployee function, but when it would reach the repository which is a mock it would work as expected.
If it is in fact the whole service you want to mock then instantiate it using #Mock instead of #InjectMocks.
I'm working to unit test my Java app..
My goal is to use Powermock to create a spy on an instance of the BOProcessor class. BOProcessor has a final void method; I will setup my spy to throw an exception when this method is called. I will also be mocking MyDao in this same test, but mocking this class is straightforward. The mocked MyDao will then be passed into an instance of MyDaoService named classUnderTest. I will then make assertions against classUnderTest.
Whenever I try to setup the above scenario, Powermock (or Mockito?) throws an InvalidUseOfMatchersException when I setup the doThrow on my spy. Strangely, this exception is only thrown when the doThrow expectation is followed by a call to classUnderTest. If I remove the later call the classUnderTest, the expectation works fine. Even weirder - classUnderTest doesn't even use the spy that is throwing the error!
This is the entirety of my test code outlined above. To highlight the problem, I've removed all code not directly related. (I've even removed the whole purpose of this test.)
package my.package;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import org.junit.Test;
public class WhatAmIDoingWrong {
#Test
public void whatAmIDoingWrong() {
MyDao mockedDao = mock(MyDao.class);
BOProcessor processor = new BOProcessor();
BOProcessor mockedProcessor = spy(processor);
MyDaoService classUnderTest = new MyDaoService(mockedDao);
doThrow(new Exception()).when(mockedProcessor).process(any(FakeBusinessObject.class));
classUnderTest.interactWithDao();
}
}
Here is the exception - thrown (ironically) from the doThrow line of my test code - which I'm trying to solve.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at my.package.WhatAmIDoingWrong.whatAmIDoingWrong(WhatAmIDoingWrong.java:21)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
at my.package.MyDaoService.interactWithDao(MyDaoService.java:33)
at my.package.WhatAmIDoingWrong.whatAmIDoingWrong(WhatAmIDoingWrong.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Here are the classes used by my test. To reiterate, the MyDaoService named classUnderTest doesn't even know about the spy of BOProcessor; it only works against the mock of MyDao. But the expectations on the BOProcessor spy only fail if the classUnderTest is called.
public class BOProcessor {
public final void process(FakeBusinessObject bar) {}
}
public class FakeBusinessObject {
}
import java.util.Collections;
import java.util.List;
public class MyDao {
public MyDao() {}
public List<String> getAllData(){
return Collections.emptyList();
}
}
public class MyDaoService {
private MyDao applicationDao;
public MyDaoService(MyDao applicationDao) {
this.applicationDao = applicationDao;
}
public synchronized void interactWithDao() {
applicationDao.getAllData();
}
}
I'm usin JUnit 4.12, Mockito 1.10.19, and Powermock 1.7.4. The project is running Spring 4.3.12RELEASE with spring-test included.
Why is Powermock throwing this exception? Am I not using the any Matcher correctly? Why on earth is this exception only thrown when a later call interacts with a different mock?
Thanks for the help!
It turns out that I was using Spies wrong. Something in the way org.mockito.stubbing.Stubber.when(T mock) is implemented means I cannot set expectations on the Spy the way I wanted to. But a Capture was actually a better fit for my use case anyway.
In the end, my test looked like this:
public class FixedNow{
#Test
public void fixedNow() {
MyDao mockedDao = mock(MyDao.class);
BOProcessor mockedProcessor = mock(BOProcessor.class);
FakeBusinessObject problematicBO = new FakeBusinessObject();
ArgumentCaptor<FakeBusinessObject> fakeBOCaptor = ArgumentCaptor.forClass(FakeBusinessObject.class);
MyDaoService classUnderTest = new MyDaoService(mockedDao, mockedProcessor);
doThrow(new Exception()).when(mockedProcessor).process(eq(problematicBO));
doNothing().when(mockedProcessor).process(fakeBOCaptor.capture());
classUnderTest.interactWithDao();
assertThings(BOCaptor.getValue());
}
}
Thanks for your thoughts!
I have a very complicated class to write Junit test case. I decided to use PowerMockito since my class for which the test is to be run has a constructor initialization.
My main class is like this:
public class MainClass extends BaseClass{
MainClass(SomeClass class){
super(class);
}
public void methodToBeTested(){
some code here
}
..few other methods which I am not going to test.
}
Now I have the test case written like this:
#RunWith(PowerMockRunner.class)
public class TestClass{
#Mock
OtherClassUsedInMainClass mock1;
#Mock
OtherClassUsedInMainClass mock2;
#InjectMocks
MainClass mainClass;
#Before
public void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class))
.thenReturn(mainClass);)
}
#Test
public void testMethodtobeTested(){
...I am using the other objects to mock data and test if this method works fine
mainClass.methodtobeTested();
\\This method will increment a value. I am just asserting if that value is right.
Assert.assertEquals(mainClass.checkCount(),RequiredCount)
}
}
I am getting a null pointer exception when running the Testcase since it tries to initialize the mainClass. It does not get mocked. I know I am doing something wrong. But I just don't know what it is.
Error:
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'mainClass' of type 'class com.main.MainClass'.
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 : null
Caused by: java.lang.NullPointerException
This null pointer exception is thrown from a the constructor of the BaseClass when it tries to initialize another class.
This question explains the difference between #Mock and #InjectMocks:
#Mock creates a mock. #InjectMocks creates an instance of the class and injects the mocks that are created with the #Mock (or #Spy) annotations into this instance.
MainClass constructor expects a SomeClass parameter but there isn't any mock for that.
Your code should be something like:
#RunWith(PowerMockRunner.class)
public class TestClass{
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeClass mock1;
#InjectMocks
MainClass mainClass;
#Before
public void setUp() throws Exception{
...
Quoting this answer, which is quoting the #InjectMocks documentation:
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. Note: If arguments can not be found, then null is passed.
So, presumably, declare a field of type SomeClass, and annotate it #Mock.
If you can't show us the actual code it is very hard to guess what exactly is happening. But it looks like your mock SomeClass needs some stubbed behavior to satisfy the BaseClass constructor.
For example:
// the instance of MainClass you run your tests against
private MainClass instance;
#Mock
private SomeClass someClass;
#Mock
private SomethingElse somethingElse;
#Before
public void setUp() {
when(someClass.doSomething()).thenReturn(somethingElse);
instance = new MainClass(someClass);
}
#Test
public void test() {
// SETUP
when(somethingElse.doWeirdStuff()).thenThrow(new WeirdException());
// CALL
instance.performTapDance();
// VERIFY
assertTrue(instance.isWeird());
}