Test argument of a void method with Mockito - java

Is it possible to test the values of an instance passed as an argument to a method that is void using Mockito?
public String foo() {
Object o = new ObjectX();
o.setField("hi");
someDao.boo(o);
return "response";
}
boo is void and I want to test that foo sets the field to "hi"

Perhaps you would want to use doNothing method.
#Mock
SomeDao someDao;
#Captor
ArgumentCaptor<ObjectX> captor;
#Test
void test() {
doNothing().when(someDao).boo(captor.capture());
foo();
assertEquals("hi", captor.getValue().getField());
}

Updated
this is what JB in my comments is suggesting.
#RunWith(MockitoJUnitRunner.class)
public class BarTest
{
#Mock
private SomeDao someDao;
#InjectMocks
private Bar bar;
#Before
public void initMocks()
{
MockitoAnnotations.initMocks(this);
}
#Test
public void testFoo()
{
Mockito.doAnswer(new Answer<Object>()
{
#Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
ObjectX x = (ObjectX) invocation.getArguments()[0];
Assert.assertEquals("hi", x.getField());
return null;
}
}).when(someDao).boo(Mockito.any(ObjectX.class));
Assert.assertEquals("response", bar.foo());
}
}
This below is my first answer and correct in its own way.
No it's not possible with Mockito, since ObjectX is a new Object within the void method, to accomplish this with Mockito then you would have to pass ObjectX in as an argument to the method foo(). You might want to look into Powermock if your code can't be changed.
public String foo(ObjectX objectX) {
Object o = objectX;
o.setField("hi");
someDao.boo(o);
return "response";
}
Test case
#Test
public void testFoo()
{
ObjectX mock = Mockito.mock(ObjectX.class);
Assert.assertEquals("response", foo(mock));
Mockito.verify(mock, Mockito.times(1)).setField(Mockito.eq("hi"));
}

Related

Mocking a method inside a private method

I have the below flow
#InjectMocks private ClassToTest classToTest;
#Mock private ClassToInject classToInject;
#Before
public void setup() {
initMocks(this);
}
#Test
public void test() {
Classx mockClassObj = Mockito.mock(Classx.class);
when(classToInject.publicMethod1(mockClassObj)).thenReturn(1000);
classToTest.publicMethod();
}
I want to test public method of classToTest. Now this method makes call to a private method, which I am not mocking. Inside this private method another public method is called, which I want to mock publicMethod1. Instead of the private method making use of value 1000 it is behaving as if the publicMethod1 was not mocked and I get NPE inside the flow of the method somewhere. I tried using #Spy with classToTest and also I am using init.mocks/#RunWith but it fails.
In short it is something like
ClassToTest. publicMethod --> ClassToTest.privateMethod(not mocking) --> ClassToInject.publicMethod1(want to mock)
The class looks like below
class ClassToTest {
#Inject ClassToInject classToInject;
public publicMethod() {
privateMethod();
}
private privateMethod() {
int x = classToInject.publicMethod1();
// use the return value
// throw exception
}
You mock classToInject.publicMethod1(mockClassObj) not classToInject.publicMethod1().
But your code invoked classToInject.publicMethod1();
int x = classToInject.publicMethod1(); // you invoked no parameter method
Check method which you want to invoke.
If You want to invoke classToInject.publicMethod1(), reference this code
#RunWith(MockitoJUnitRunner.class)
public class MockedTest {
#InjectMocks
private ClassToTest classToTest;
#Mock
private ClassToInject classToInject;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
Mockito.when(classToInject.publicMethod1())
.thenReturn(1000);
classToTest.publicMethod();
}
}
class ClassToTest{
ClassToInject classToInject;
public void publicMethod() {
privateMethod();
}
private int privateMethod() {
int x = classToInject.publicMethod1();
throw new NullPointerException(String.valueOf(x));
}
}
class ClassToInject{
public int publicMethod1() {
return 0;
}
}
The result is 1000 success
java.lang.NullPointerException: 1000

Writing a Junit test for a boolean method with no parameters

I have a class where I want to write a junit test for.
This method has no parameters, can this method accordingly?
public class classTobeTested {
#Self
SlingHttpServletRequest request;
static final String keyword = "hello";
public boolean isActive() {
boolean check;
String pathChecker;
pathChecker = (request.getRequestURL()).toString();
check= pathChecker.contains(keyword);
return check;
}
}
This would be the testing class i had in mind
#RunWith(MockitoJUnitRunner.class)
public class testclasstobetested {
#Test
public void TestclassTobeTested() throws Exception{
classTobeTested CTT = new classTobeTested();
assertFalse(CTT.isActive("hello how are you"));
}
}
I know my method does not take a parameter but has strings declared inside the method.
How can i use assertFalse correctly to test a non param method.
Using annotations and Junit4 you can do it like this:
#RunWith(MockitoJUnitRunner.class)
public class testclasstobetested {
#InjectMocks
private classTobeTested CTT;
#Mock
private SlingHttpServletRequest request;
#Test
public void TestclassTobeTested() throws Exception{
when(request.getRequestURL()).thenReturn(new StringBuffer("hello how are you"));
assertFalse(CTT.isActive());
}
}

Mocking constructor using PowerMockito doesn't work

I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.

Mockito - Impossible stubbing mocked object

I am newbie in Java world, but it is very hard understand why not can I stub method of a mocked object...
#RunWith(MockitoJUnitRunner.class)
public class ChildBLLIT extends BaseInteractorIT {
#InjectMocks
private ChildBLL ChildBLL = Mockito.mock(ChildBLL.class);
#Before
public void setUp() {
ChildBLL.engine = engineMock;
}
/**
* Test of getZipStatistics method, of class ChildBLL.
*/
#Test
public void testGetZipStatistics() {
final String testZipStatisticsText = "DummyZipStatistics";
//This method will throw the null pointer exception
when(ChildBLL.engine.getZIPStatistics()).thenReturn(testZipStatisticsText);
ChildBLL.getZipStatistics();
verify(ChildBLL.engine).getZIPStatistics();
}
}
When I try to stub the getZIPStatistics() method I get always a null pointer exception, of course I get, because in the getZIPStatistics() method there is an private object, which is not mocked... it seems to me the Mockito does not mocking the private fields... and unfortunately this is from another project:
public class BaseIT {
#Mock
protected static FromOtherProject engineMock;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}
Here I mocked the engine variable, but then how can I mock/stub the getZIPStatistics() method? This is this method:
public class FromOtherProject {
//...
public final String getZIPStatistics() {
return ZIPStatistics.toString();
}
}
What can I do?
Let's assume a simple class...
public class Account {
public String getPassword() {
return "abc";
}
}
...and simple class that contains it...
public class AccountHolder {
private Account account;
public String getAccountPassword() {
return this.account.getPassword();
}
}
So now we have a simple base class for all Account based tests...
public class AccountBasedTest {
#Mock
protected Account account;
}
...and a class that actually tests the AccountHolder...
#RunWith(MockitoJUnitRunner.class)
public class AccountHolderTest extends AccountBasedTest {
#InjectMocks
private AccountHolder accountHolder;
#Test
public void getAccountPasswort_must_return_account_password() {
Mockito.when( this.account.getPassword() ).thenReturn ("xyz");
Assert.assertEquals("xyz", this.accountHolder.getAccountPassword());
}
}
And that's all. The #InjectMocks, etc. annotations will also look in the superclasses, so you get your mocked account and that account will be put into your AccountHolder. No need to call MockitoAnnotations.initMocks. It shouldn't hurt, but it's not needed because you are using the MockitoJUnitRunner already, which does exactly that.

How to call real methods in class instances annotated with #Injectable in JMockit?

I'm looking for a way in JMockit to inject the private fields inside a class while maintaining the ability to trigger the real methods. I use #Injectable and #Tested offered by JMockit. But somehow after that the injected instance is not able to call the real method.
Example test:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
doSomething.execute();
}
}
Here DoSomething wraps the Call instance, which provides a way to print a message. The ideal output of the four test cases would be:
real
real
real
fake
However the actual scenario is that only 3 and 4 worked, printing:
real
fake
This shows if an instance is created using #Injectable. It's not able to directly call the original method without copying and pasting the old method body to the mocked version. That seems really awkward. Is there a workaround of this?
My understanding is that if you use #Injectable you just get an empty mock and then you can no longer call the original method.
The workaround that I would use is to do the injection "manually" like this:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
//#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
}
I ran into this question when I had the same problem. However, the existing answer don't work with newer versions of JMockit.
If a field in the tested class is annotated with #Inject, a corresponding #Injectable is required in the test class. Usually. This means that removing the #Injectable and instead mock the class with MockUp suggested in the other answer doesn't work. JMockit will complain with "Missing #Injectable for field ...".
What needs to be done instead is to change the #Injectable annotation to a #Tested annotation, i.e. change this
#Injectable Call call;
to
#Tested Call call;
call becomes a real instance and JMockit doesn't complain about a missing #Injectable. If you need to mock some methods in call, it can be done with MockUp as usual.
new MockUp<Call>() {
#Mock
public void someMethodToMock() {
}
};

Categories