Is it possible to invoke mocked object's method? - java

I have, for example, this class:
public class A {
private List<String> list;
public A(B b){
list = b.getList();
}
public List<String> someMethod(){
return list;
}
}
I want to unit test someMethod without invoking constructor. I use reflection to set list.
The problem is that I don't want to create B class object and I cannot mock it since it will cause NPE.
So my question is:
How to test someMethod without calling constructor of A? Is there any way to mock class A and doesn't lose posibility to call methods?
Creating constructor with zero arguments is not a solution.
Note: I don't want to change any part of A class. I'm asking if it is possible to perform this test without adding or changing anything in A class.

You can test class A without calling it's constructor by Mockito. Not sure if I really understand your requirement but the following codes work for me.
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ATest {
#Test
public void test() {
A a = mock(A.class);
when(a.someMethod()).thenCallRealMethod();
List<String> listInA = new ArrayList<String>();
ReflectionTestUtils.setField(a, "list", listInA);
assertThat(a.someMethod(), is(listInA));
}
}

You should mock out the collaborators to your class -- that means that you can create an instance of the class being tested, and pass in mocks, configured to 'do the right thing' when it's methods are called.
In your example, you want to create a mock B, and use it like this:
#RunWith(MockitoJUnitRunner.class)
class myTest {
#Mock private B b;
public void someMethod() {
doReturn(new ArrayList<String>()).when(b).getList();
A a = new A(b);
assertEquals("result", a.someMethod().get(0));
}
}

I don't want to create B class object
Add a constructor or factory method which doesn't require a B.
public A(B b){
this(b.getList());
}
/* package local */ A(List<String> list){
this.list = list;
}
By making the constructor package local it can be accessed by unit tests in the same package.
How to test someMethod without calling constructor of A?
You can use
A a = theUnsafe.allocateInstance(A.class);
but this is not recommended unless you have no other option e.g. deserialization.

Related

How to mock super function of abstract class which is called by a function of sub class

I am writing a unit test for a class which extends from abstract class, one function of sub class will call super void function and function.
//two classes in different package
public abstract class AbstractBo {
private Map myMap = new HashMap();
protected void load(String jsonString) {
//convert the jsonString parameter to map, and set to myMap
}
public String getItem(String key) {
return myMap(Key);
}
}
public class SubBo extends AbstractBo {
public String submit(String initString) {
//init a map by super function
this.load(initString);
return this.getItem("myName");
}
}
I just want to test submit function, mock the load and getItem function. I am new to powermock.
As a rule of thumb, you should try to avoid Powermock as far as you can, since it's usually associated with bad code design.
You actually don't need to use it in this case, since Mockito covers this case with spies, which is itself a bad code smell as stated in the documentation.
My suggestion is to change the code using composition over inheritance.
Still, if you are stuck with the code as it is, just add Junit and Mockito to your dependencies and write a test like:
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class SubBoTest {
#Test
public void shouldBehaveAsExpected() {
final String expected = "expected String";
final String testString = "test string";
final SubBo bo = spy(SubBo.class);
doNothing().when(bo).load(eq(testString));
when(bo.getItem("myName")).thenReturn(expected);
final String actual = bo.submit(testString);
assertEquals(expected, actual);
}
}
Again, please be reminded that this is not the proper way to go, and refactoring is advisable.

How to capture incoming parameters with EasyMock.capture?

I'm testing a class and wanted to monitor calls to a specific method, namely to save the calling parameters for later analysis.
Testing is done with EasyMock, so it was logical to use EasyMock.capture feature. However, the examples that I managed to find do not work for me - I get the following compile error at the line with capture:
expect(T) in EasyMock cannot be applied to (void)
reason: no instance of type variable T exist so that void conforms to T
It would be great if somebody could point out my mistake(s) for me. Below is a code snippet:
import static org.easymock.EasyMock.capture;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
class B {
}
class A {
public void doSomething(B input) {
}
}
public class ATest {
private Capture<B> capturedData;
private A testObject;
#Before
private void setUp() {
capturedData = EasyMock.newCapture(CaptureType.ALL);
testObject = EasyMock.createNiceMock(A.class);
EasyMock
.expect(testObject.doSomething(capture(capturedData)))
.anyTimes();
}
}
Thanks a lot in advance!
Your problem is not related to the capture, but to the return type of your doSomething() method:
Since A.doSomething(B input) is of return type void, you don't expect the method to return anything, thus you cannot use EasyMock.expect() for it. Instead, simply invoke the method and use EasyMock.expectLastCall(), like so:
testObject.doSomething(capture(capturedData));
EasyMock.expectLastCall().anyTimes();
EasyMock.expectLastCall() declares that you expect the last method invocation before expectLastCall() to be executed. You can then handle it just like expect(), e.g. add anyTimes() to it.

Powermock not intercepting new object creation

I am attempting to test a method that creates a new instance of another class that I wish to mock using powermock. My code (simplified) is as follows -
Testing code:
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.easymock.EasyMock.anyObject;
import static org.powermock.api.easymock.PowerMock.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest( { ClassUnderTest.class } )
public class TestForClassUnderTest {
private ClassToBeMocked classToBeMocked;
private ClassUnderTest classUnderTest;
public void testSimple() throws Exception {
classToBeMocked = createMock(ClassToBeMocked.class);
// trying to intercept the constructor
// I *think* this is the root cause of the issue
expectNew(ClassToBeMocked.class, anyObject(), anyObject(), anyObject()).andReturn(classToBeMocked);
classToBeMocked.close();
expectLastCall();
replayAll();
// call to perform the test
classUnderTest.doStuff();
}
}
Code that is being tested:
import ClassToBeMocked;
public class ClassUnderTest {
private ClassToBeMocked classToBeMocked;
public void doStuff() {
classToBeMocked = new ClassToBeMocked("A","B","C");
// doing lots of other things here that I feel are irrelevant
classToBeMocked.close();
}
}
Code that I wish to mock:
public class ClassToBeMocked {
public ClassToBeMocked(String A, String B, String C) {
// irrelevant
}
public close() {
// irrelevant
}
}
The error I get is as below:
java.lang.ExceptionInInitializerError
at ....more inner details of where this goes into
at ClassToBeMocked.close
at ClassUnderTest.doStuff
at TestForClassUnderTest.test.unit.testSimple
Caused by: java.lang.NullPointerException
PowerMock version:1.4.5
EasyMock version: 3.1
PS: I have stripped down the code to bare minimums, only showing the details of the mocking library, let me know if you think my other code is somehow interfering and I can give more details on the bits you think are important to show. Any links to other examples doing this may even help.
I realized that the reason this wasn't working was because I was extending another class. I had
#RunWith(PowerMockRunner.class)
#PrepareForTest( { ClassUnderTest.class } )
public class TestForClassUnderTest extends AnotherClass {
}
as soon as I removed the extends, it worked. Not sure if its just not able to extend another class with powermock or due to AnotherClass, but removing it worked for me
whenever you wish to mock a new instance of any class, you should be doing like this
Powermock.expectNew(ClassYouWishToMock.class).andReturn(whateverYouWantToReturn).anyTimes();
Powermock.replayAll();
this will return 'whateverYouWantToReturn' whener new is called on this class.
but whenever you want to mock a instance variable, you should be using Whitebox feature of easymock.
have a look at following Example
Class A{
private B b;
}
to mock this my test class will look something like this
...//other powermock, easymock class level annotations
#PrepareForTest(B.class)
class ATest{
Whitebox.setInternalState(B.class,b,whateverValueYouWantYourMockedObjectToReflect);
}
here 'b' passed in parameter, is the variable name you want to mock.
Good Luck!

Test if another method was called

So I'm sure there is something like this out there but I have been searching for an hour and haven't found exactly what I am looking for. say I have a class that looks like this:
public class MyClass
{
public void myMethod(boolean shouldCallOtherMethod)
{
if(shouldCallOtherMethod)
{
otherMethod();
}
}
public void otherMethod()
{
System.out.println("Called");
}
}
How do I make something like this work?
#Test
public void shouldCallMethod()
{
MyClass myClass = new MyClass();
myClass.myMethod(true)
// verify myClass.otherMethod method was called
}
Using Mockito, you can do spying on real objects like this:
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyClassTest {
#Test
public void otherMethodShouldBeCalled() {
MyClass myClass = new MyClass();
MyClass spy = spy(myClass);
spy.myMethod(true);
verify(spy).otherMethod();
}
}
There are some gotchas, so take a look at the relevant documentation as well.
Suppose MokeysClass has a constructor declared like this, where Foo is some other class.
public MokeysClass(String name, int counter, Foo myFoo)
I would write my test like this.
#RunWith(MockitoJUnitRunner.class)
public class TestArray {
#Mock
private Foo mockMyFoo;
private String nameToInject = "Mokey";
private int counterToInject = 42;
#Spy
private MokeysClass toTest = new MokeysClass(nameToInject, counterToInject, mockMyFoo);
#Test
public void shouldCallMethod() {
toTest.myMethod(true);
verify(toTest).otherMethod();
}
}
so that I am explicitly stating which constructor to call when I create my test object, and what arguments to pass to it.
There are some reasons not to rely on #InjectMocks to do this step for me, particularly if the class being tested is more complex and has more than one constructor. Mockito chooses the constructor that has the most arguments, but if there are several constructors with the same number of arguments, Mockito could choose any of the constructors; that is, the behaviour is undefined.
Once Mockito has chosen a constructor, it checks whether that constructor can in fact be used for constructor injection. Constructor injection will not be used if
one or more of the parameters of the chosen constructor is a primitive type,
the type of one or more of the parameters of the chosen constructor is a final class,
the type of one or more of the parameters of the chosen constructor is a private class,
the only constructor of the class is the default constructor.
If any one of these conditions holds, for the constructor that Mockito chose, then constructor injection won’t be used. In this case, the class must have a default constructor, otherwise Mockito will throw an exception.
The complexity of the criteria which Mockito uses when choosing whether to apply constructor injection implies that adding or removing a constructor, or changing the parameters of a constructor, can make Mockito switch from using constructor injection to using setter and field injection; or from using setter and field injection to using constructor injection. This can occur even if the constructor that is changed is not the one that will be used for constructor injection.
As a result, any test that uses constructor injection is automatically quite brittle; in the sense that changes that are not directly related to the test itself can cause the test to fail. Such failures can be difficult to troubleshoot.
The #InjectMocks annotation was designed for use with frameworks such as Spring that do dependency injection; and for tests of classes that use Spring, it can be invaluable. But if dependency injection is not part of your class, I would strongly recommend avoiding #InjectMocks on account of its brittleness. You really want your test code to be as easy to maintain and to troubleshoot as your production code is.
This is not recommended, but you can spy real object :)
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.BDDMockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Spy
private MyClass sut; // System Under Test
#Test
public void shouldCallMethod() {
// when
sut.myMethod(true);
// then
verify(sut).otherMethod();
}
}
Result:
Tests Passed: 1 passed in 0,203 s
After changing code: sut.myMethod(false);
Wanted but not invoked:
sut.otherMethod();
-> at my.custom.MyClassTest.shouldCallMethod(MyClassTest.java:23)
Source: Spying on real objects
Magic version with constructor injection
#Mock
private LexAnalyzer lexAnalyzer;
#Spy
#InjectMocks
private SyntaxAnalyzer sut; // System Under Test
#Test
public void shouldCallMethod() {
// when
sut.myMethod(true);
// then
verify(sut).otherMethod();
}
SyntaxAnalyzer.java
public class SyntaxAnalyzer {
private final LexAnalyzer lexAnalyzer;
public SyntaxAnalyzer(LexAnalyzer lexAnalyzer) {
this.lexAnalyzer = lexAnalyzer;
}
...
Tested, works ;)
I think you want to look at Mock objects. You can create a mock of MyClass, then set expectations that otherMethod() is called when you call myMethod and fails if it was not called.
Here is a pretty good overview of them for java - http://www.scalatest.org/user_guide/testing_with_mock_objects
One other major benefit of using Mocks, you can avoid side affects, like logging to NSLog or hitting a web server or printing) in your test.

Consecutive calls testing in Mockito

I have simple service
package net.betlista;
import java.util.List;
public class MyServiceImpl implements MyService {
MyDao dao;
public void saveAll(final List<Integer> list) {
for (final int i : list) {
dao.save(i);
}
}
void setDao(final MyDao dao) {
this.dao = dao;
}
}
and DAO
package net.betlista;
public class MyDaoImpl implements MyDao {
public void save(final Integer i) {
// do nothing, ok for tests
}
}
and I want to test with Mockito that when I call service.saveAll(), that save() call is called for all instances in list:
package net.betlista;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
public class MyServiceTest {
#Test
public void test() {
final MyDao daoMock = Mockito.mock(MyDao.class);
final MyServiceImpl service = new MyServiceImpl();
service.setDao(daoMock);
final List<Integer> list = new LinkedList<Integer>();
list.add(1);
list.add(2);
service.saveAll(list);
// not working, it's ok, should fail
// Mockito.verify(daoMock).save(Matchers.eq(1));
// Mockito.verify(daoMock).save(Matchers.eq(1));
final InOrder inOrder = Mockito.inOrder(daoMock);
inOrder.verify(daoMock).save(1);
inOrder.verify(daoMock).save(1); // change 1 to 2 to fix test
Mockito.verify(daoMock);
}
}
the commented part is not working = it passes, but should fail.
Using InOrder, works but in fact I'm not interested in order (for example if using set instead of list, order is not known).
Any idea, or I'm just trying to do something senseless?
The best way to do this is with an ArgumentCaptor.
service.saveAll(list);
ArgumentCaptor<Integer> values = ArgumentCaptor.forClass(Integer.class);
verify(daoMock, times(list.size())).save(values.capture());
assertEquals(list, values.getAllValues());
The ArgumentCaptor gives you access to all of the values that were ever passed to this method. So there's no need to worry about whether this method was called "extra" times; and no problem in the case where the same value occurs twice in the original list.
I want to test with Mockito that when I call service.saveAll(), that save() call is called for all instances in list
OK, then how about this:
service.saveAll(list);
for (int i:list)
{
Mockito.verify(daoMock).save(Matchers.eq(i));
}
I'm not entirely sure why you think the commented out lines should fail, but I'm guessing that its because you want to make sure its only called once? If so, then the reason it passes it because it has only been called once, however, your test code is verifying twice that it was only called once which isn't much use. The above code will verify that the save method was called once (and only once) for each item in the list.
Mockito.verify(daoMock, Mockito.times(2)).save(Matchers.eq(1));
Since you are verifying the same value, use times()
However, the better way to test that there are exactly the number of invocations you want is to use verifyNoMoreInteractions
So the test would be like this:
verify(daoMock).save(1);
verify(daoMock).save(2);
verifyNoMoreInteractions(daoMock);

Categories