Powermock private stubbing gows wrong - java

Im trying to make a simple as a can example which could be found on official PowerMock's page (here).I' doing a partial mock of this class :
public class Simple {
public String doMe() {
return privateMethod();
}
private String privateMethod() {
return "POWERMOCK sucks";
}
}
And wrote a simple test class :
#RunWith(PowerMockRunner.class)
#PrepareForTest(Simple.class)
public class ProcessorTest {
#Test
public void doMe() throws Exception {
Simple spy = PowerMockito.spy(new Simple());
PowerMockito.doReturn("hello").when(spy, "privateMethod");
String res = spy.doMe();
PowerMockito.verifyPrivate(spy, Mockito.times(1000)).invoke(
"privateMethod");
Assert.assertEquals( res, "hello");
}
}
But result is like this :
java.lang.AssertionError: expected [hello] but found [null]
Expected :hello
Actual :null
<Click to see difference>
at org.testng.Assert.fail(Assert.java:94)
So Powermock not only fails to mock the privateMethod and return 'null' it's OK with that it was called 1000 times when it was not.
It get even more creepy if I try to mess with mocking like this :
PowerMockito.doReturn(1).when(spy, "privateMethod");
So I'm trying to return an Integer instead of String from the privateMethod.
Then I get this :
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Integer cannot be returned by doMe()
doMe() should return String
***
So by some reason Powermock is trying to mock public doMe method.
Any one understands what is happining? I dont.
Thanks.
My environment is :
Java 1.8, Mockito 1.10.19, Powermock 1.6.2

Ok, I found solution, the problem was that JUnit's #RunWith did not actually do the trick so I had to extend from PowerMockTestCase to make it work. The test looks like this now and it works like a charm:
#PrepareForTest(Simple.class)
public class ProcessorTest extends PowerMockTestCase {
#Test
public void doMe() throws Exception {
Simple spy = PowerMockito.spy(new Simple());
PowerMockito.doReturn("hello").when(spy, "privateMethod");
String res = spy.doMe();
PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke(
"privateMethod");
Assert.assertEquals( res, "hello");
}
}

Related

spring test mock static method globally

in spring test, I know I can mock static method(usually static util methods: generate id, get value from Redis) using Mockito like:
try (MockedStatic) {
}
but having to do this in every test method is ugly and cumbersome, is there any way to do it all(i am ok to have a single mocked behavior)
I am thinking maybe a junit5 extension, or Mockito extension, this seems like a common problem, I wonder if anyone tries something with any success.
try this
public class StaticClassTest {
MockedStatic<YourStatic> mockedStatic;
#Before
public void setup() {
mockedStatic = Mockito.mockStatic(YourStatic.class);
// if you want the same behavior all along.
mockedStatic.when(() -> YourStatic.doSomething(anyString())).thenReturn("TEST");
}
#Test
public void test_static() {
// write your test here
}
#After
public void teardown() {
mockedStatic.close();
}
}

Creating a test method for a function resulted in WebClientResponseException$NotFound: 404 Not Found

I have the following service method
public List<Object> init() {
List<Object> listForAutoCompleteAndPicklists = new ArrayList<>();
listForAutoCompleteAndPicklists.add(getCore());
listForAutoCompleteAndPicklists.add(setPickList());
listForAutoCompleteAndPicklists.add(Collections.singletonList(setStudyTypeAndDesign()));
listForAutoCompleteAndPicklists.add(getMonitors());
return listForAutoCompleteAndPicklists;
}
with getCore(), setPickList(),... as other functions inside the service. Is it possible to test this kind of method? I came up with
#Test
#DisplayName("Test init")
void init() {
List<Object> response;
response = vaultServiceTest.init();
response.add(1, vaultServiceTest.getBasCore());
response.add(2, vaultServiceTest.setPickList());
response.add(3, vaultServiceTest.setStudyTypeAndDesign());
response.add(4, vaultServiceTest.getMonitors());
assertEquals(4, response.size());
}
But that resulted in WebClientResponseException$NotFound: 404 Not Found.
A unit test on init()should suffice. A test on this public method covers the side effects of the private methods

Junit Test: findById method of the Repository

I am new in Junit tests and I have a question about it. Here you can see the method findById in my service class:
#Service
public class DefaultQuarterService implements QuarterService {
private final QuarterRepository quarterRepository;
public DefaultQuarterService(QuarterRepository quarterRepository) {
this.quarterRepository = quarterRepository;
}
#Override
public QuarterEntity findById(int id) {
return quarterRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(String.format("Quarter does not exist for id = %s!", id)));
}
}
And here is my QuarterRepository:
#Repository
public interface QuarterRepository extends CrudRepository<QuarterEntity, Integer> {
}
And here is my Junit implementation for this method:
#MockBean
private QuarterRepository quarterRepository;
#Test
public void throwExceptionWhenQuarterIdNotFound() {
int id = anyInt();
when(quarterRepository.findById(id))
.thenReturn(Optional.empty());
assertThatAnExceptionWasThrown(String.format("Quarter does not exist for id = %s!", id));
}
public void assertThatAnExceptionWasThrown(
String errorMsg
) {
expectException.expect(RuntimeException.class);
expectException.expectMessage(errorMsg);
}
Unfortunately test doesn't pass. Here the error in terminal:
java.lang.AssertionError: Expected test to throw (an instance of
java.lang.RuntimeException and exception with message a string
containing "Quarter does not exist for id = 0!")
Maybe it is so simple but I can not see what I am missing. I would be so happy if you can direct me. Thanks a lot!
As you mock your Repository it will return with Optional.empty() correctly, I think you should call your service's (which is Autowired) findById method. It will throw the exception actually.
First issue
In the assertThatAnExceptionWasThrown method you expect RuntimeException BUT in the service class you throw EntityNotFoundException, So I guess you should expect EntityNotFoundException in your test case.
Second issue
After this part of the code.
when(quarterRepository.findById(id))
.thenReturn(Optional.empty());
Why didn't you call your service method (findById)?
When you are returning the empty value, you should verify your condition with the service method you want to test it.
It should be something like this.
assertThatThrownBy(() -> defaultQuarterService.findById(id))
.isInstanceOf(ApiRequestException.class)
.hasMessageContaining("PUT_YOUR_EXCEPTION_MESSAGE_HERE");
This is a good sample for unit-test in the spring boot. You can check it out. Link
Try the above solutions and let me know it has been fixed or not. Good luck

Powermockito : java.lang.IllegalArgumentException: argument type mismatch

I don't have much experience with Mocking, I have recently started using it in my Junit test cases. However, I am having difficulties understanding the execution.
I am getting IllegalArgumentException when I try this code
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
But when I provide the values that the lockUser would recieve at the time of execution, everything works as expected.
Working code
PowerMockito.doNothing().when(spyObject, "lockUser", "my_text", userMock);
I am rather confused with this behavior. I was expecting identical behaviour.
Could someone explain why this is happening ?
In addition when I have the following code
PowerMockito.doNothing().when(spyObject, "lockUser", anyString(), anyObject());
The method is no longer mocked and the real method is invoked.
Interestingly I have another method with same name "lockUser" which takes different number of parameters. And in my other test method, I have used only Matchers (anyObject(), anyString() etc) and that works as expected.
PowerMockito.doNothing().when(spyObject, "lockUser", anyObject(), anyString(), anyString(), anyString());
All lockUser methods are priavate.
I am working with Mockito 1.9.5 together with PowerMock 1.5.6
Any help is greatly appreciated
Edit
Additional Code to make it clear
Class Core {
public Worker getWorker(String workerId) {
// Get worker from Map<String, Worker> fID_WRK with workerId as key
// Get user from worker (I have mocked this part, so my mock user is
// returned)
If(user.isTooOld()) {
lockUserAndNotify(reason, user);
throw new UserLockedException("Too old");
}
private void lockUserAndNotify(String reason, User user) {
lockUserAndNotify(reason, user.fname, user.lname); // locks user and notifies
}
public getUser(String login, String password) {
// find user in database
if(user password is too old) {
lockUserAndNotify(dbConnection, fname, lname, userId);
}
}
private lockUserAndNotify(Connection dbConn, String fName, String lName, String
userId) {
//method call to lock the user
//method call to notify the admin
}
}
My Test class
Class CoreTest {
#Test (expected = UserLockedException.class)
public void getUser_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
when(userMock.isPwdUpdateTimeExpired()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyObject(), anyString(), anyString(), anyString(), anyString());
admin4.UserManager.getUser("l.user1","password");
}
#Test (expected = UserLockedException.class)
public void getWorker_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
Map workerMap = Whitebox.getInternalState(coreSpy, "fID_WRK");
Map workerMapSpy = PowerMockito.spy(workerMap);
when(workerMapSpy.getWorker("12345")).thenReturn(workerMock);
when(workerMock.getUser()).thenReturn(userMock);
when(userMock.isTooOld()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyString(), anyObject());
admin4.UserManager.getWorker("123445");
}
}
So the test getUser_ThrowsException works as expected, but getWorker_ThrowsException does not.
To answer the part of your question about IllegalArgumentException: argument type mismatch, you get this because you're using the API incorrectly when you use
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
See the documentation of PowerMocktioStubber.when, relevant section reproduced here -
public static <T> org.mockito.stubbing.OngoingStubbing<T> when(Class<?> klass,
Object... arguments)
throws Exception
Expect calls to private static methods without having to specify the method name. The method will be looked up using the parameter types if possible
Throws:
Exception - If something unexpected goes wrong.
See Also:
Mockito#when(Object)}
As you've already observed you can use either the values of the real parameters or your can use Matchers like anyString.
Here's some sample code to demonstrate this -
public class Core {
public String getWorker(String workerId) {
if (workerId.isEmpty()) {
lockUser("Reason", workerId);
}
return workerId;
}
private void lockUser(String reason, String user) {
}
}
and the corresponding tests -
#RunWith(PowerMockRunner.class)
#PrepareForTest(Core.class)
public class CoreTest {
#Test
// this is incorrect usage and throws an IllegalArgumentException
public void test1() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", String.class, String.class);
spy.getWorker("");
}
#Test
public void test2() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", Mockito.anyString(), Mockito.anyString());
spy.getWorker("");
PowerMockito.verifyPrivate(spy).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
#Test
public void test3() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", "abc", "Reason");
spy.getWorker("abc");
PowerMockito.verifyPrivate(spy, Mockito.times(0)).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
}
Without compilable code or the exception that you get for getWorker_ThrowsException, it's not possible to answer why that doesn't work as expected. I can take a look again once you add the required information.

Spy a method parameter while testing with Mockito?

Suppose that I have a class like;
public class FooBar {
public int getMethod(List<String> code){
if(code.size() > 100)
throw new Exception;
return 0;
}
}
and I have a test class like this;
#RunWith(PowerMockRunner.class)
#PrepareForTest(FooBar.class)
public class FooBarTest{
FooBar fooBarInstance;
#Before
public void setUp() {
//MockitoAnnotations.initMocks(this);
fooBarInstance = new FooBar();
}
#Test(expected = Exception.class)
public void testGetCorrelationListCodesParameter() {
List<String> codes = Mockito.spy(new ArrayList<String>());
Mockito.doReturn(150).when(codes).size();
fooBarInstance.getMethod(codes);
}
}
How can I make this test method to throw an exception ? I've dealing for hours to do this. Well thanks anyway.
Spying is not needed, mocking is enough. As #David said, also mocking is not needed and not recommended for value object.
Using #Test(expected = Exception.class) has many drawbacks, test can pass when exception is thrown from not expected places. Test is not working but is visible as green.
I prefer BDD style testing with catch-exception.
Reasons for using catch-exceptions
(...) in comparison to the use of try/catch blocks.
The test is more concise and easier to read.
The test cannot be corrupted by a missing assertion. Assume you forgot to type fail() behind the method call that is expected to throw an exception.
(...) in comparison to test runner-specific mechanisms that catch and verify exceptions.
A single test can verify more than one thrown exception.
The test can verify the properties of the thrown exception after the exception is caught.
The test can specify by which method call the exception must be thrown.
The test does not depend on a specific test runner (JUnit4, TestNG).
import static com.googlecode.catchexception.CatchException.caughtException;
import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.*;
public class FooBarTest {
FooBar sut = new FooBar(); // System Under Test
#Test
public void shouldThrowExceptionWhenListHasTooManyElements() {
when(sut).getMethod(listWithSize(150));
then(caughtException()).isInstanceOf(Exception.class);
}
private List<String> listWithSize(int size) {
return new ArrayList<String>(Arrays.asList(new String[size]));
}
}
Full working code for this test: https://gist.github.com/mariuszs/8543918
Not recommended solution with expected and mocking.
#RunWith(MockitoJUnitRunner.class)
public class FooBarTest {
#Mock
List<String> codes;
FooBar fooBarInstance = new FooBar();
#Test(expected = Exception.class)
public void shouldThrowExceptionWhenListHasTooManyElements() throws Exception {
when(codes.size()).thenReturn(150);
fooBarInstance.getMethod(codes);
}
}
A list is a value object. It's not something we should mock. You can write this whole test without mocking anything, if you're prepared to build a list that has a size in excess of 100.
Also, I prefer to use JUnit's ExpectedException mechanism, because it lets you check which line of the test method threw the exception. This is better than passing an argument to the #Test annotation, which only lets you check that the exception was thrown somewhere within the method.
public class FooBarTest {
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
private FooBar toTest = new FooBar();
#Test
public void getMethodThrowsException_whenListHasTooManyElements() {
List<String> listWith101Elements =
new ArrayList<String>(Arrays.asList(new String[101]));
exceptionRule.expect(Exception.class);
toTest.getMethod(listWith101Elements);
}
}

Categories