I am trying to unit test one of my methods using PowerMock and Mockito and getting NUllPointerException for one of the objects which I have already mocked and defined behavior in my test.
This is the code I am trying to test
protected void setTabList() {
List<ActionBar.Tab> list = TabAdapter.get().getAllEnabledTabs();
listAdapter.setTabList(list);
int itemCount = list.size();
if (itemCount == 1 && list.get(0).equals(TabAdapter.KEYPAD_TAB)) {
header.setVisibility(View.VISIBLE);
listAdapter.hide();
}
}
And this is the test code
#RunWith(PowerMockRunner.class)
#PrepareForTest({Log.class, TabFragment.class, TextView.class, SystemProperties.class})
public class TabFragmentTests extends TestCase {
#Before
public void setUp() {
suppress(method(Log.class, "println_native"));
suppress(everythingDeclaredIn(TextView.class));
suppress(method(SystemProperties.class, "native_get_boolean"));
suppress(method(SystemProperties.class, "native_get", String.class));
tabFragment = new TabFragment();
listAdapter = Mockito.mock(TabList.class);
}
#Test
public void testSetTabList() {
assertNotNull(tabFragment);
assertNotNull(listAdapter);
TabAdapter instance = TabAdapter.get();
TabAdapter spy = spy(instance);
List<ActionBar.Tab> list = new ArrayList<ActionBar.Tab>();
list.add(KEYPAD_TAB);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "set Tabs";
}
}).when(listAdapter).setTabList(list);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "hide";
}
}).when(listAdapter).hide();
doReturn(list).when(spy).getAllEnabledTabs();
tabFragment.setTabList();
verify(listAdapter, times(1)).hide();
}
When I run the test and tabFragment.setTabList() is called, listAdapter in setTabList() throws NPE. I am trying to understand why listAdapter.setTabList(list) is not replaced by the "answer" API I have in the test.
I have also tried using Mockito.doNothing().when(listAdapter).setTabList(list) but that doesn't solve the issue.
Another observation is when I create a dummy getTestString(listAdapter) method in my TabFragment class and call it using tabFragment.getTestString(listAdapter) from my test passing mocked listAdapter as an argument, it doesn't through a NPE. Does that mean I have to explicitly pass mocked object to the method call?
You are overriding a method call like this:
when(listAdapter).setTabList(list);
but then you call it like this:
tabFragment.setTabList();
I don't see how that would work. setTabList(list); and setTabList(); call different methods.
I think that you forgot to add "TabAdapter" class to the "PrepareForTest" annotation :
#PrepareForTest({Log.class, TabAdapter.class, TabFragment.class, TextView.class, SystemProperties.class})
Related
I have the following Java method:
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = new ESBUrlHelper().getEsbUrl();
AppointmentClient appointmentClient = AppointmentClientFactory.getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
The method above makes a call to a third party REST client called appointmentClient.
The issue that I am having is that this is causing my test to fail.
How can I mock the appointmentClientobject within my unit tests?
Currently my test looks as follows:
#Test
public void shouldAddAppointment() {
// act
Appointment appointment = appointmentService.addAppointment(CLIENT_STRING, appointmentMock)
// assert
assertNotNull(appointment);
}
But I get the following error at line appointmentClient.addAppointment(client, appointment);:
org.jboss.resteasy.client.exception.ResteasyIOException: IOException
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
I want to mock something like as follows:
Mockito.when(appointmentClient.addAppointment(client, appointment)).thenReturn(appointmentMock);
You can try using PowerMockito for this.
First, you need to mock the static method call of AppointmentClientFactory class like below:
PowerMockito.mockStatic(AppointmentClientFactory.class);
PowerMockito.when(AppointmentClientFactory,"getUnsecuredClient",esbUrl).thenReturn(appointmentClient);
And also, when you use PowerMockito for mocking static methods, add the #PrepareForTest({AppointmentClientFactory.class}) annotation to the test class.
With your current code, the only way of mocking a call to AppointmentClientFactory#getUnsecuredClient would be using PowerMock, since the factory method is static. This is due to the hard coupling between your calling code addAppointment and the dependency here (i.e. the AppointmentClientFactory).
If I were you, I would avoid that as PowerMock is not the best way to do tests. Instead, what I would do, would be to inject the AppointmentClientFactory as a dependency thus allowing me to mock an instance of it during my tests.
This should be the best approach in twofold manner. Firstly, because you achieve less tightly coupled code and secondly because you do not need to use PowerMock for your unit-tests.
It's not impossible with Mockito. But your original problem is static method of AppointmentClientFactory. You definitely should change this method to the instance method (at least for better architecture) , for example:
public class AppointmentClientFactory {
public AppointmentClient getUnsecuredClient(String url) {
return new AppointmentClient(); //your implementation
}
}
Then your AppointmentService will look like (or close to it):
public class AppointmentService {
private final AppointmentClientFactory factory;
public AppointmentService() {
this(new AppointmentClientFactory());
}
public AppointmentService(AppointmentClientFactory factory) {
this.factory = factory;
}
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = "";
Appointment outputAppointment = null;
AppointmentClient appointmentClient = new AppointmentClientFactory().getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
}
And then you will could write test like:
public class AppointmentTest {
private final String CLIENT_STRING = "";
#Test
public void shouldAddAppointment() {
AppointmentClientFactory clientFactory = Mockito.mock(AppointmentClientFactory.class);
AppointmentClient mockedClient = Mockito.mock(AppointmentClient.class);
AppointmentService service = new AppointmentService(clientFactory);
Appointment appointmentMock = new Appointment();
when(clientFactory.getUnsecuredClient(any())).thenReturn(mockedClient);
Appointment appointment = service.addAppointment(CLIENT_STRING, appointmentMock);
assertNotNull(appointment);
}
}
When I used Powermock to mock a private method, and then verify it in another method's unit test, to check if it was called and with correct times. But I found I can verify whether the method was called and with the correct param, the called times of the method can be any number, however the unit test always passed. If someone can help me solve the problem. thx!
This is my source code:
public enum ConversionCommon{
INSTANCE;
...
public void getConvertTypeData(JSONObject result, JSONObject conversionData, String intent){
String uncertainty = "";
String unit1 = "";
String unit1_char = "";
if(result.has(ConversionDefine.CONVERSION_UNCERTAINTY)){
uncertainty = result.getString(ConversionDefine.CONVERSION_UNCERTAINTY);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1)){
unit1 = result.getString(ConversionDefine.CONVERSION_UNIT1);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1_CHAR)){
unit1_char = result.getString(ConversionDefine.CONVERSION_UNIT1_CHAR);
}
setUnitCount(conversionData, uncertainty, intent);
setDestUnits(conversionData, unit1, unit1_char);
}
}
The method getConvertTypeData() calls two methods once. The follow is my test case code:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ConversionCommon.class, LengthConversion.class })
#PowerMockIgnore("javax.management.*")
public class ConversionCommonTest{
#Before
public void setUp() throws Exception{
PowerMockito.mockStatic(LengthConversion.class);//
PowerMockito.spy(LengthConversion.class); //
}
#Test
public void should_getConvertTypeData_invoke_setUnitCount() throws Exception{
JSONObject result = new JSONObject();
JSONObject conversionData = new JSONObject();
result.put(ConversionDefine.CONVERSION_UNCERTAINTY, "3");
result.put(ConversionDefine.CONVERSION_UNIT1, "meter");
result.put(ConversionDefine.CONVERSION_UNIT1_CHAR, "centmeter");
suppress(method(ConversionCommon.class, "setUnitCount", JSONObject.class, String.class, String.class));
ConversionCommon.INSTANCE.getConvertTypeData(result, conversionData, ConversionDefine.INTENT_LENGTH_CONVERSION);
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(1)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
}
The test case can run successful but if I change the last line to ...
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(100)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
... and re-run the test case. The result is also passed. But in fact I only call the method setUnitCount only once in Refo.
The edition of test framework: mockito:1.10.19;powermock:1.6.5
How can I correct verify the private method's call times with the API PowerMockito.verifyPrivate();
You are doing right, except one thing. You're spying on enum constant. And each enums constant is separate inner class. So you have to add two things:
Enum constant to #PrepareForTest with using fullyQualifiedNames, like `#PrepareForTest(values = { ConversionCommon.class, LengthConversion.class }, fullyQualifiedNames = "com.somepackage.ConversionCommon$INSTANCE")
Create a spy for instance: PowerMockito.spy(ConversionCommon.INSTANCE)
Replace constant with spy: Whitebox.setInternalState(ConversionCommon.class, spy)
Now, you can stub the spy method as usual doNothing().when(spy, "setUnitCount");
Code snippet for some abstract singleton implement via enum:
enum
public enum Singleton {
INSTANCE;
public void doSomething(){
callPrivateMethod();
}
private void callPrivateMethod() {
}
}
test
RunWith(PowerMockRunner.class)
#PrepareForTest(value = Singleton.class, fullyQualifiedNames = "com.stackoverflow.q46212600.Singleton$INSTANCE")
public class ClassUseSingletonTest {
#Test
public void should_verify_enum_method() throws Exception {
final Singleton spy = PowerMockito.spy(Singleton.INSTANCE);
Whitebox.setInternalState(Singleton.class, spy);
doNothing().when(spy, "callPrivateMethod");
new ClassUseSingletone().doSomething("do");
PowerMockito.verifyPrivate(Singleton.INSTANCE, times(1)).invoke("callPrivateMethod");
}
}
Full example, you may find here
I would like to check if a private method of my class to test is executed or not using powermockito.
Suppose that I have this class to test:
public class ClassToTest {
public boolean methodToTest() {
//doSomething (maybe call privateMethod or maybeNot)
return true;
}
//I want to know if this is called or not during the test of "methodToTest".
private void privateMethod() {
//do something
}
}
When I test "methodToTest" I want to check if it returns the correct result but also if it executes the private method "privateMethod" or not.
Searching on other discussion I wrote this test that makes use of powermockito but it doesnt works.
public class TestClass {
#Test
testMethodToTest(){
ClassToTest instance = new ClassToTest();
boolean result = instance.methodToTest();
assertTrue(result, "The public method must return true");
//Checks if the public method "methodToTest" called "privateMethod" during its execution.
PowerMockito.verifyPrivate(instance, times(1)).invoke("privateMethod");
}
}
When I use the debugger it seems that the last line (PowerMockito.verifyPrivate...) doesn't check if the private method has been executed once during the test but instead it seems that it executes the private method itself. Furthermore the test passes but using the debugger I'm sure that the private method is not executed during the call of "instance.methodToTest()".
What is wrong?
I'd do it easier way, without PowerMockito. Consider this (it's some kind of Spy object):
public class TestClassToTest {
private boolean called = false;
#Test
public void testIfPrivateMethodCalled() throws Exception {
//given
ClassToTest classToTest = new ClassToTest() {
#Override
void privateMethod() {
called = true;
}
};
//when
classToTest.methodToTest();
//then
assertTrue(called);
}
}
This requires changing privateMethod() to package-private (but there's nothing wrong with this).
But bear in mind, that testing implementation is a bad practise and can lead to fragile tests. Instead you should test only results.
public class Holder() {
Contact contact1;
Contact contact2;
}
public class ContactServiceImpl() {
public Contact create(Contact contact) {
// do create
}
}
public class HolderServiceImpl() {
ContactService contactService = new ContactServiceImpl();
public Holder createHolder(Holder holder) {
contactService.create(holder.getContact1());
contactService.create(holder.getContact2());
return holder;
}
}
pulbic class HolderServiceTest() {
ContactServiceImpl contactService = new ContactServiceImpl();
HolderServiceImpl holderService = new HolderServiceImpl();
#Before
public void setUp() {
contactService = EasyMock.createMock(ContactServiceImpl.class);
holderService.setContactServiceImpl(contactService);
EasyMock.expect(contactService.create(EasyMock.isA(Contact.class))).andReturn(new Contact()).anyTimes();
}
#Test
public void testCreate() {
Holder holder = new Holder();
holderService.create(holder)
}
}
When not setting the replay, I have an error on the second call of contactService.create which is IllegalStateException.
However when adding (After the expect call) :
EasyMock.replay(contactService);
I get this error:
Unexpected method call ContactServiceImpl.create(Contact#4ebd441a[
I tried using PowerMock but I get the same issue. Is it even possible to have both calls like that? Anytimes() seems to exist for that use but it's not working much.
You never did put the mock in replay state. Just add EasyMock.replay(contactService); at the end of your setUp method.
Actually what was wrong is that my method testCreate was missing the setters on contact1 and contact2 which caused the error.
I had the option of either:
Setting both objects
Using EasyMock.isNull(Contact.class) instead of EasyMock.isA(Contact.class).
However since it was possible for in real cases to have either one of them as null, the best solution was to use EasyMock.anyObject(Contact.class) which accepts both initiated objects or nulls.
#Before
public void setUp() {
contactService = EasyMock.createMock(ContactServiceImpl.class);
holderService.setContactServiceImpl(contactService);
EasyMock.expect(contactService.create(EasyMock.anyObject(Contact.class))).andReturn(new Contact()).anyTimes();
}
I am using Mockito for service later unit testing. I am confused when to use doAnswer vs thenReturn.
Can anyone help me in detail? So far, I have tried it with thenReturn.
You should use thenReturn or doReturn when you know the return value at the time you mock a method call. This defined value is returned when you invoke the mocked method.
thenReturn(T value) Sets a return value to be returned when the method is called.
#Test
public void test_return() throws Exception {
Dummy dummy = mock(Dummy.class);
int returnValue = 5;
// choose your preferred way
when(dummy.stringLength("dummy")).thenReturn(returnValue);
doReturn(returnValue).when(dummy).stringLength("dummy");
}
Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.
Use doAnswer() when you want to stub a void method with generic Answer.
Answer specifies an action that is executed and a return value that is returned when you interact with the mock.
#Test
public void test_answer() throws Exception {
Dummy dummy = mock(Dummy.class);
Answer<Integer> answer = new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
String string = invocation.getArgumentAt(0, String.class);
return string.length() * 2;
}
};
// choose your preferred way
when(dummy.stringLength("dummy")).thenAnswer(answer);
doAnswer(answer).when(dummy).stringLength("dummy");
}
doAnswer and thenReturn do the same thing if:
You are using Mock, not Spy
The method you're stubbing is returning a value, not a void method.
Let's mock this BookService
public interface BookService {
String getAuthor();
void queryBookTitle(BookServiceCallback callback);
}
You can stub getAuthor() using doAnswer and thenReturn.
BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return "Joshua";
}
}).when(service).getAuthor();
Note that when using doAnswer, you can't pass a method on when.
// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());
So, when would you use doAnswer instead of thenReturn? I can think of two use cases:
When you want to "stub" void method.
Using doAnswer you can do some additionals actions upon method invocation. For example, trigger a callback on queryBookTitle.
BookServiceCallback callback = new BookServiceCallback() {
#Override
public void onSuccess(String bookTitle) {
assertEquals("Effective Java", bookTitle);
}
};
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
callback.onSuccess("Effective Java");
// return null because queryBookTitle is void
return null;
}
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
When you are using Spy instead of Mock
When using when-thenReturn on Spy Mockito will call real method and then stub your answer. This can cause a problem if you don't want to call real method, like in this sample:
List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));
Using doAnswer we can stub it safely.
List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));
Actually, if you don't want to do additional actions upon method invocation, you can just use doReturn.
List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
The simplest answer is:
If you need a fixed return value on method call then we should use thenReturn(…)
If you need to perform some operation or the value need to be computed at run time then we should use thenAnswer(…)