I am new with Mockito and I wanted to write a unit test for some legacy code. I did try few techniques mentioned for using mockito while testing my specific scenario but I am not able to find a solution to my usecase. Here is my scenario :
I have a method A( does local processing of data) and a method B (does some remote processing of data). Method A in turn calls my method B. I want to call method A and when it in turn calls method B, then I want to return a predefined value from method B, lets says a list of files. Here is the sample code from Test class and actual class:
Myclass mc = Mockito.mock(MyClass.class);
when(mc.methodB(param1,param2)).thenReturn(fileSet); // returns mocked fileSet (set of files)
when(mc.methodA(param1,param2)).thenCallRealMethod(); //calls real method A
mc.methodA(param1,param2); //does not return the mocked value from methodB
class MyClass{
public Set<File> methodB(param1,param2){
//some processing
return fileSet;
}
public void methodA(param1,param2){
//some processing
Set<FileSet> fileSet = methodB(param1,param2);
//some more processing on returned files
}
}
I created a mock of my class and made sure that when I invoke method A, real method call for method A happens and when I invoke method B, mock results are returned.
If I test method A and method B separately it works but when I call method A which in turn calls method B, it does not return my mocked value from method B.
Is this not the right way of doing this call or am I missing something?
If I understand correctly, you want to mock one method from a class while really calling another method from the same class.
This can be done using spies: with spies, every method from the object is really called, unless it was explicitely stubbed:
MyClass myClass = new MyClass();
MyClass spy = spy(myClass); // creates a spy for myClass
doReturn(new HashSet<File>() {{ add(new File("file1")); }}).when(spy).methodB("", ""); // stubbing method B
spy.methodA(param1, param2); // calling the real method A
Note that spies should be used carefully, only to deal with legacy code that you cannot change.
Note that the construct to stub methodB differs from the "usual" construct. If we write the following code:
when(spy.methodB("", "")).thenReturn(...);
what is happening is that the real methodB is getting actually called right here, and this is something we do not want. In the second construct:
doReturn(...).when(spy).methodB("", "");
the methodB is not called.
Here's a complete test class demonstrating spies:
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
public class TestClass {
#Test
public void test() {
MyClass myClass = new MyClass();
MyClass spy = spy(myClass); // creates a spy for myClass
doReturn(new HashSet<File>() {{ add(new File("file1")); }}).when(spy).methodB("", ""); // stubbing method B
spy.methodA("", ""); // calling the real method A
}
}
class MyClass {
public Set<File> methodB(String param1, String param2) {
return new HashSet<File>() {{ add(new File("file2")); }};
}
public void methodA(String param1, String param2) {
Set<File> fileSet = methodB(param1, param2);
System.out.println(fileSet); // prints [file1] and not [file2], meaning the stubbed method was called and not the real one
}
}
Related
I have a function that is calling a method from another class. This class and method have been tested and are using live data which makes my test inconsistent with the expected values I hard coded.
public class MyClass{
public void functionToBeTested(String params){
//stuff to do
Caller call = new Caller();
callResult = call.post(someJSON);
//do stuff with callResult
}
}
Here is the junit:
public class TestMyClass{
MyClass testClass = new MyClass();
Caller mock;
#Before
public void setup(){
premadeAnswer = new String(file);
mock = Mockito.mock(Caller.class);
Mockito.when(mock.post(Mockito.any())).thenReturn(premadeAnswer);
}
#Test
public void studentFees_CorrectSSN(){
assertEquals(expected.getThing(), testClass.functionToBeTested("PARAMS").getThing());
}
}
I was pretty sure I did everything right but obviously its not mocking and instead calling the function ans behaving as expected if it wasn't a junit. If I had to make a guess as to whats happening it would be that even though I am creating a mocked object and using when/thenReturn it is not attached to MyClass testClass object.
That won't work because Caller is not injected into functionToBeTested function.
Mockito.when(mock.post(Mockito.any())).thenReturn(premadeAnswer);
this when statement is working only on your mocked instance, inside functionToBeTested you are creating a new instance of Caller.
Either change functionToBeTested(String params) to functionToBeTested(String params, Caller call) and then pass your mocked Caller instance or try mocking Caller constructor.
More info about second approach here
I noticed in your first block of code that you shared, that there is no return value specified. I added void in the code block below.
public class MyClass{
public void functionToBeTested(String params){
//stuff to do
Caller call = new Caller();
callResult = call.post(someJSON);
//do stuff with callResult
}
}
Code sample :
public class A{
public static B connectA(){
String new = "java";
B b = new B("new");
return b;
}
public void A(){
B b = connectA();
}
}
public class B{
public B(String A){
methodB(new);
}
public static String methodB(String new){
return new;
}
}
So, now if i am testing method "A", :
when it calls "connectA() method", i want it to return a mocked object that i want
OR
when "new B" is called i want it to return a mocked object i want
it works if the connectA() method is not static, but i dont know how to make it work if its static using powermockito and mockito
so test class would be somethinng like:
#RunWith(PowerMockRunner.class)
#PrepareForTest({A.class,B.class})
public class ATest(){
public void testMethodA(){
PowerMockito.whenNew(B.class).withAnyArguments().thenReturn(BMock);
A a = new A();
a.A();
}
}
where BMock is any object i create!
Any possible solutions ?
Try add
PowerMockito.mockStatic(A.class);
PowerMockito.mockStatic(B.class);
But I would refactor code and use com.google.inject.Provider for creating instance of B class. It is easy to mock it and you wouldn't need PowerMockito.
Update.
This code works correct for me(I add getter within class A)
package main;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.mockito.Mockito;
#RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
#PrepareForTest({A.class,B.class})
public class ATests{
#Test
public void testMethodA() throws Exception{
B BMock = Mockito.mock(B.class);
PowerMockito.whenNew(B.class).withAnyArguments().thenReturn(BMock);
A a = new A();
Assert.assertEquals(BMock, a.getB());
}
}
According injectors.
See reference https://github.com/google/guice/wiki/InjectingProviders
It is dificult to understand what do you want and what is the logic in your class. So only you know your business rule and where to inject. Instead Providers you can use factories. But there is a "holy war" about using factories.
So the answer to this would be,
when i do mock like this :
PowerMockito.mockStatic(B.class);
PowerMockito.when(B.methodB).thenReturn("My mocked String");
then here ("My mocked string") is a different instance of object that is used or we can say has different object id (like : a5Gbd#ass)
but when actually the method is called in the constructor of method B, it is called with this variable passed in as "new", which again has a different object id (like : affac#das), so what happens is powermockito thinks that the method which is called now in the constructor and the method which we are referring to when we are mocking it - both are different.
and that is why its said as one of the limitation of powermockito.
but i had a work around for this, it would work if somehow you are able to pass the same instance of object at both the places, this way powermockito knows we are reffering to same method.
again, it depends on how your code is structured , but in my code i saw it was possible and so it helped.
one more thing that helped me was accessing a private variable using powermockito, so if anyone needs it:
Whitebox.getInternalState(classObjectNameCreated, "variableName");
ask questions, if nothing is understood, i know i am not good at it!! :)
I have interface with declared method
public interface EventAdder{
void addEvent(Event e);
}
now I got a class where this interface is used.
public class Container{
//some code here
private EventAdder ea;
public void checkPainterState(){
//some code which I want to test inside checkPainterState
ea.addEvent(new Event(val1, val2));
}
}
I am using outside test class where I create Container object.
I want to test method checkPainterState() without calling ea.addEvent() in checkPainterState() method in tests. How I can mock/spy/replace this ea object or ea.AddEvent method in tests to prevent use?
Since you use mockito, it is as easy as to declare:
final EventAdder adder = mock(EventAdder.class);
// make it the adder for your container, run the method, then
verify(adder).addEvent(any(Event.class)); // or other argument matcher
The default behaviour of void methods when you mock it with Mockito is precisely to do nothing.
I have a static method, that is used in multiple places, mostly in static initialization block. It takes a Class object as parameter, and returns the class's instance.
I want to mock this static method only when particular Class object is used as parameter. But when the method is called from other places, with different Class objects, it returns null.
How can we have the static method execute actual implementation in case of parameters other than the mocked one?
class ABC{
void someMethod(){
Node impl = ServiceFactory.getImpl(Node.class); //need to mock this call
impl.xyz();
}
}
class SomeOtherClass{
static Line impl = ServiceFactory.getImpl(Line.class); //the mock code below returns null here
}
class TestABC{
#Mocked ServiceFactory fact;
#Test
public void testSomeMethod(){
new NonStrictExpectations(){
ServiceFactory.getImpl(Node.class);
returns(new NodeImpl());
}
}
}
What you want is a form of "partial mocking", specifically dynamic partial mocking in the JMockit API:
#Test
public void testSomeMethod() {
new NonStrictExpectations(ServiceFactory.class) {{
ServiceFactory.getImpl(Node.class); result = new NodeImpl();
}};
// Call tested code...
}
Only the invocations that match a recorded expectation will get mocked. Others will execute the real implementation, when the dynamically mocked class is called.
I have a class as below:
public class A {
public A(String test) {
bla bla bla
}
public String check() {
bla bla bla
}
}
The logic in the constructor A(String test) and check() are the things I am trying to mock. I want any calls like: new A($$$any string$$$).check() returns a dummy string "test".
I tried:
A a = mock(A.class);
when(a.check()).thenReturn("test");
String test = a.check(); // to this point, everything works. test shows as "tests"
whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk);
// also tried:
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk);
new A("random string").check(); // this doesn't work
But it doesn't seem to be working. new A($$$any string$$$).check() is still going through the constructor logic instead of fetch the mocked object of A.
The code you posted works for me with the latest version of Mockito and Powermockito. Maybe you haven't prepared A?
Try this:
A.java
public class A {
private final String test;
public A(String test) {
this.test = test;
}
public String check() {
return "checked " + this.test;
}
}
MockA.java
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class MockA {
#Test
public void test_not_mocked() throws Throwable {
assertThat(new A("random string").check(), equalTo("checked random string"));
}
#Test
public void test_mocked() throws Throwable {
A a = mock(A.class);
when(a.check()).thenReturn("test");
PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
assertThat(new A("random string").check(), equalTo("test"));
}
}
Both tests should pass with mockito 1.9.0, powermockito 1.4.12 and junit 4.8.2
To my knowledge, you can't mock constructors with mockito, only methods. But according to the wiki on the Mockito google code page there is a way to mock the constructor behavior by creating a method in your class which return a new instance of that class. then you can mock out that method. Below is an excerpt directly from the Mockito wiki:
Pattern 1 - using one-line methods for object creation
To use pattern 1 (testing a class called MyClass), you would replace a call like
Foo foo = new Foo( a, b, c );
with
Foo foo = makeFoo( a, b, c );
and write a one-line method
Foo makeFoo( A a, B b, C c ) {
return new Foo( a, b, c );
}
It's important that you don't include any logic in the method; just the one line that creates the
object. The reason for this is that the method itself is never going
to be unit tested.
When you come to test the class, the object that you test will
actually be a Mockito spy, with this method overridden, to return a
mock. What you're testing is therefore not the class itself, but a
very slightly modified version of it.
Your test class might contain members like
#Mock private Foo mockFoo;
private MyClass toTest = spy(new MyClass());
Lastly, inside your test method you mock out the call to
makeFoo with a line like
doReturn( mockFoo )
.when( toTest )
.makeFoo( any( A.class ), any( B.class ), any( C.class ));
You can use matchers that are more specific than any() if you want to
check the arguments that are passed to the constructor.
If you're just wanting to return a mocked object of your class I think this should work for you. In any case you can read more about mocking object creation here:
http://code.google.com/p/mockito/wiki/MockingObjectCreation
With Mockito you can use withSettings(). For example if the CounterService required 2 dependencies, you can pass them as a mock:
UserService userService = Mockito.mock(UserService.class);
SearchService searchService = Mockito.mock(SearchService.class);
CounterService counterService = Mockito.mock(CounterService.class, withSettings().useConstructor(userService, searchService));
Starting with version 3.5.0 of Mockito and using the InlineMockMaker, you can now mock object constructions:
try (MockedConstruction mocked = mockConstruction(A.class)) {
A a = new A();
when(a.check()).thenReturn("bar");
}
Inside the try-with-resources construct all object constructions are returning a mock.
Without Using Powermock .... See the example below based on Ben Glasser answer since it took me some time to figure it out ..hope that saves some times ...
Original Class :
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(new BClazz(cClazzObj, 10));
}
}
Modified Class :
#Slf4j
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(getBObject(cClazzObj, 10));
}
protected BClazz getBObject(CClazz cClazzObj, int i) {
return new BClazz(cClazzObj, 10);
}
}
Test Class
public class AClazzTest {
#InjectMocks
#Spy
private AClazz aClazzObj;
#Mock
private CClazz cClazzObj;
#Mock
private BClazz bClassObj;
#Before
public void setUp() throws Exception {
Mockito.doReturn(bClassObj)
.when(aClazzObj)
.getBObject(Mockito.eq(cClazzObj), Mockito.anyInt());
}
#Test
public void testConfigStrategy() {
aClazzObj.updateObject(cClazzObj);
Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj);
}
}
Mockito has limitations testing final, static, and private methods.
Alternate Solution:
with jMockit testing library, you can do few stuff very easy and straight-forward as below:
Mock constructor of a java.io.File class:
new MockUp<File>(){
#Mock
public void $init(String pathname){
System.out.println(pathname);
// or do whatever you want
}
};
the public constructor name should be replaced with $init
arguments and exceptions thrown remains same
return type should be defined as void
Mock a static method:
remove static from the method mock signature
method signature remains same otherwise
Using Mockito 4 (but I suspect this is true for Mockito from 3.5.0 version) you can mock the constructor and, in the initializer, you can assert the values of the parameters.
For example:
try (MockedConstruction<A> constr = mockConstruction(A.class,
(mock, context) -> {
if (context.getCount() == 1) {
assertArrayEquals(context.arguments().toArray(), new Object[] {"test"});
} else {
fail("No more calls should happen");
}
})) {
// Do the rest of assertions.
}
Notice that you need to put the MockedConstruction instantiation in a try-with-resources otherwise the mocked construction is leaked outside the test.