Mocking methods of local scope objects with Mockito - object

I need some help with this:
Example:
void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
I want to mock obj1.method1() in my test but to be transparent so I don't want make and change of code.
Is there any way to do this in Mockito?

The answer from #edutesoy points to the documentation of PowerMockito and mentions constructor mocking as a hint but doesn't mention how to apply that to the current problem in the question.
Here is a solution based on that. Taking the code from the question:
public class MyClass {
void method1 {
MyObject obj1 = new MyObject();
obj1.method1();
}
}
The following test will create a mock of the MyObject instance class via preparing the class that instantiates it (in this example I am calling it MyClass) with PowerMock and letting PowerMockito to stub the constructor of MyObject class, then letting you stub the MyObject instance method1() call:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
#Test
public void testMethod1() {
MyObject myObjectMock = mock(MyObject.class);
when(myObjectMock.method1()).thenReturn(<whatever you want to return>);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(myObjectMock);
MyClass objectTested = new MyClass();
objectTested.method1();
... // your assertions or verification here
}
}
With that your internal method1() call will return what you want.
If you like the one-liners you can make the code shorter by creating the mock and the stub inline:
MyObject myObjectMock = when(mock(MyObject.class).method1()).thenReturn(<whatever you want>).getMock();

If you really want to avoid touching this code, you can use Powermockito (PowerMock for Mockito).
With this, amongst many other things, you can mock the construction of new objects in a very easy way.

No way. You'll need some dependency injection, i.e. instead of having the obj1 instantiated it should be provided by some factory.
MyObjectFactory factory;
public void setMyObjectFactory(MyObjectFactory factory)
{
this.factory = factory;
}
void method1()
{
MyObject obj1 = factory.get();
obj1.method();
}
Then your test would look like:
#Test
public void testMethod1() throws Exception
{
MyObjectFactory factory = Mockito.mock(MyObjectFactory.class);
MyObject obj1 = Mockito.mock(MyObject.class);
Mockito.when(factory.get()).thenReturn(obj1);
// mock the method()
Mockito.when(obj1.method()).thenReturn(Boolean.FALSE);
SomeObject someObject = new SomeObject();
someObject.setMyObjectFactory(factory);
someObject.method1();
// do some assertions
}

Both mocking of a new instance creation and static methods is possible without PowerMock in the latest mockito versions and junit5.
Take a look in the methods Mockito.mockConstruction() and Mockito.mockStatic().
In your case:
try (MockedConstruction<MyObject> myobjectMockedConstruction = Mockito.mockConstruction(MyObject.class,
(mock, context) -> {
given(mock.method1()).willReturn("some result"); //any additional mocking
})) {
underTest.method1();
assertThat(myobjectMockedConstruction.constructed()).hasSize(1);
MyObject mock = myobjectMockedConstruction.constructed().get(0);
verify(mock).method1();
}

You could avoid changing the code (although I recommend Boris' answer) and mock the constructor, like in this example for mocking the creation of a File object inside a method. Don't forget to put the class that will create the file in the #PrepareForTest.
package hello.easymock.constructor;
import java.io.File;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({File.class})
public class ConstructorExampleTest {
#Test
public void testMockFile() throws Exception {
// first, create a mock for File
final File fileMock = EasyMock.createMock(File.class);
EasyMock.expect(fileMock.getAbsolutePath()).andReturn("/my/fake/file/path");
EasyMock.replay(fileMock);
// then return the mocked object if the constructor is invoked
Class<?>[] parameterTypes = new Class[] { String.class };
PowerMock.expectNew(File.class, parameterTypes , EasyMock.isA(String.class)).andReturn(fileMock);
PowerMock.replay(File.class);
// try constructing a real File and check if the mock kicked in
final String mockedFilePath = new File("/real/path/for/file").getAbsolutePath();
Assert.assertEquals("/my/fake/file/path", mockedFilePath);
}
}

If you don't prefer to use PowerMock, you may try the below way:
public class Example{
...
void method1(){
MyObject obj1 = getMyObject();
obj1.doSomething();
}
protected MyObject getMyObject(){
return new MyObject();
}
...
}
Write your test like this:
#Mock
MyObject mockMyObject;
#Test
void testMethod1(){
Example spyExample = spy(new Example());
when(spyExample.getMyObject()).thenReturn(mockMyObject);
//stub if required
doNothing().when(mockMyObject.doSomething());
verify(mockMyObject).doSomething();
}

You can do this by creating a factory method in MyObject:
class MyObject {
public static MyObject create() {
return new MyObject();
}
}
then mock that with PowerMock.
However, by mocking the methods of a local scope object, you are depending on that part of the implementation of the method staying the same. So you lose the ability to refactor that part of the method without breaking the test. In addition, if you are stubbing return values in the mock, then your unit test may pass, but the method may behave unexpectedly when using the real object.
In sum, you should probably not try to do this. Rather, letting the test drive your code (aka TDD), you would arrive at a solution like:
void method1(MyObject obj1) {
obj1.method1();
}
passing in the dependency, which you can easily mock for the unit test.

Related

Mockito: How to test a class's void method?

Unit test noob here.
I have three classes: Db1Dao, Db2Dao, ExecuteClass where Db1Dao, Db2Dao are database access objects for two different databases. My goal is to fetch some data from db1 using Db1Dao and run executeClass.execute() to "put" the processed data into db2 using Db2Dao.
My ExecuteClass looks like this:
class ExecuteClass {
private Db1Dao db1Dao;
private Db2Dao db2Dao;
public void execute() {
...
List<String> listOfString = getExternalData(someParam);
List<Metadata> metadatum = db1Dao.get(someInputs);
... I do something to generate a list of new class `A` based on listOfString & metadatum ...
try {
db2Dao.put(listOfA);
} catch (PutException e){
...
}
}
public List<String> getExternalData(SomeClass someParam){
... do something
return listOfString;
}
}
Now I want to test:
Given a specific listOfString (returned by getExternalData) and a specific metadatum (returned by db1Dao.get):
Will I get the desired listOfA?
Am I able to call db2Dao.put and its input parameter is listOfA?
Particularly, I have hard-coded sample listOfString and metadatum and desired listOfA (and they will be passed via an object MockData, see the following code) but I don't know how to write the test using Mockito. The following is a test class I wrote but it does not work:
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
// executeClass.execute(); not working neither...
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(listOfA);
}
}
Could anyone please let me know? Thank you in advance!!
You should not create a spy of the same class you want to test. Instead, try to write a unit test for the smallest amount of code (e.g. a public method) and mock every external operator (in your case Db1Dao and Db2Dao).
If testing a public method involves calling another public method of the same class, make sure to mock everything inside the other public method (in your case getExternalData). Otherwise, this other public method might be a good candidate for an extra class to have clear separation of concerns.
So, remove the ExecuteClass executeClassSpy = Mockito.spy(executeClass); and make sure you setup everything with Mockito what's called within getExternalData.
To now actually, verify that Db2Dao was called with the correct parameter, either use your current approach with verifying the payload. But here it's important to 100% create the same data structure you get while executing your application code.
Another solution would be to use Mockito's #Captor. This allows you to capture the value of why verifying the invocation of a mock. Later on, you can also write assertions on the captured value:
#Captor
private ArgumentCaptor<ClassOfListOfA> argumentCaptor;
#Test
public void yourTest() {
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals("StringValue", argumentCaptur.getValue().getWhateverGetterYouHave);
}
The following code worked for me.
I partially accepted #rieckpil's answer. I used #Captor which is very handy.
The reason I had to mock getExternalData() is because its implementation is still a "TODO".
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
#Captor
private ArgumentCaptor<List<A>> argumentCaptor;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals(listOfA, argumentCaptor.getValue());
}
}

Mock constructor of a class

I am writing test class for my java class. I am using Junit5 with Mockito.
I am using Junit5 which isnt compatible with Power Mockito so I am using Mockito only.
I have class Emp which have function findSalary like below and EmpProfileClient is initialized at constructor.
Class Emp {
......
public void findSalary(empId) {
...
TaxReturn taxReturn = new TaxReturn(EmpProfileClient);
int value = taxReturn.apply(new TaxReturnRequest.withEmpId(empId))
.returnInRupee();
...
}
}
When I am writing the test case, I mocked EmpProfileClient, but since we are creating TaxReturn in a method, How I can mock TaxReturn.apply so I can write the expectation to get the value as per my choice which I set in the test class?
If you want to mock this, the TaxReturn class should be an injected bean in the Emp class. Add an injection framework (like Spring) and inject the TaxReturn class. In the test you write you can inject a Mock instead of the real class. See #InjectMocks annotation of the mockito framework.
If I understood your question correctly(you are looking for mocking taxReturn.apply) I'd suggest next:
First. Refactor your taxReturn instantiation(as it is would be much easier to mock method behavior in comparison for trying to mock local variable)
public class EmpService {
public int findSalary(Integer empId) {
//...
// It's doesn't matter what the actual empProfileClient type is
// as you mocking creation behavior anyway
Object empProfileClient = null;
TaxReturn taxReturn = createClient(empProfileClient);
int value = taxReturn.apply(new TaxReturnRequest().withEmpId(empId))
.returnInRupee();
//...
return value; // or whatever
}
protected TaxReturn createClient(Object empProfileClient) {
return new TaxReturn(empProfileClient);
}
}
Second. Use Mockito.spy() in your test:
class EmpServiceTest {
#Test
void findSalary() {
TaxReturn taxReturn = Mockito.mock(TaxReturn.class);
// this is the main idea, here you using partial EmpService mock instance
// part is mocked(createClient()) and other part(findSalary()) is tested
EmpService service = Mockito.spy(EmpService.class);
when(service.createClient(any())).thenReturn(taxReturn);
when(taxReturn.apply(any(TaxReturnRequest.class))).thenReturn(taxReturn);
int yourExpectedValue = 5;
when(taxReturn.returnInRupee()).thenReturn(yourExpectedValue);
assertEquals(yourExpectedValue, service.findSalary(0));
}
}
Keep in mind that any(), spy(), when() and mock() methods are part of Mockito API. So there is nothing hidden here

How to mock constructor using Mockito

I have a question regarding one of the feature of mockito. On several blogs I have read that mocking constructor is not possible through mockito.
For one of my test case, currently it is done through powermockito but I want to remove it due to some performance issues.
Currently the code looks something like this:
Actual class:
public class TestClass {
private ClassB classB;
public TestClass(ClassB classB) {
this.classB = classB;
}
}
In my test class, I have code like this:
TestClass testClass = Mockito.mock(TestClass.class);
PowerMockito.whenNew(TestClass.class).withArguments(this.classB)
.thenReturn(testClass);
So could anyone suggest me, is there any other way possible by which I can achieve the same thing through mockito? Also on some blogs, I found that injection a public method with constructor of the class inside and then mocking that method can do the trick. But wanted to know all other options to analyze.
Thanks
-Sam
I am not sure if that can help you.
class MyClass {
private final MySecondClass clazz;
MyClass(MySecondClass clazz) {
this.clazz = clazz;
}
public boolean executeDoSomething() {
return clazz.doSomething();
}
}
And in the test you could mock the inner class:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Test
public void MyClassTest() {
MySecondClass mockedPerformer = Mockito.mock(MySecondClass.class);
MyClass clazz = new MyClass(mockedPerformer);
clazz.executeDoSomething();
}
}
I hope this helps you.

How to use PowerMockito to verify super method is called

I am testing a legacy code that use inheritance method. I am trying to mock super-method
to verity if the super-method is being call or not.
#RunWith(PowerMockRunner.class)
public class HumanTest {
#Test
public void test() throws NoSuchMethodException, SecurityException {
// 1. arrange
Human sut = PowerMockito.spy(new Human());
PowerMockito.doNothing().when((SuperHuman) sut).run(); // SuperHuman is the parent class
// 2. action
sut.run();
// 3. assert / verify
}
}
public class Human extends SuperHuman {
#Override
public void run() {
System.out.println("human run");
super.run();
}
}
public class SuperHuman {
public void run() {
System.out.println("superhuman run");
}
}
I was expecting that "human run" will be printed. But the actual result was none printed.
PowerMockito.doNothing().when((SuperHuman) sut).run(); // SuperHuman is the parent class
This won't work in your case since PowerMockito will mock method of Human even if you made cast.
I checked your code example and could say that it is possible to suppress invocation of super class method with:
Method toReplace = PowerMockito.method(SuperHuman.class, "run");
PowerMockito.suppress(toReplace);
But it seems that method replacment feature does not work for methods of super class:
createPartialMock should support mocking overridden methods in super classes.
So this does not work:
PowerMockito.replace(toReplace).with(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Method of superclass has been invoked !");
return null;
}
});
But still you should be able to verify invocation of super method let's say indirectly, by mocking other classes which are invoked in super method only.
For instance check that System.out.println was invoked with "superhuman run" or something like this.

Is private method in spring service implement class thread safe

I got a service in an project using Spring framework.
public class MyServiceImpl implements IMyService {
public MyObject foo(SomeObject obj) {
MyObject myobj = this.mapToMyObject(obj);
myobj.setLastUpdatedDate(new Date());
return myobj;
}
private MyObject mapToMyObject(SomeObject obj){
MyObject myojb = new MyObject();
ConvertUtils.register(new MyNullConvertor(), String.class);
ConvertUtils.register(new StringConvertorForDateType(), Date.class);
BeanUtils.copyProperties(myojb , obj);
ConvertUtils.deregister(Date.class);
return myojb;
}
}
Then I got a class to call foo() in multi-thread;
There goes the problem. In some of the threads, I got error when calling
BeanUtils.copyProperties(myojb , obj);
saying Cannot invoke com.my.MyObject.setStartDate - java.lang.ClassCastException#2da93171
obviously, this is caused by ConvertUtils.deregister(Date.class) which is supposed to be called after BeanUtils.copyProperties(myojb , obj);.
It looks like one of the threads deregistered the Date class out while another thread was just about to call BeanUtils.copyProperties(myojb , obj);.
So My question is how do I make the private method mapToMyObject() thread safe?
Or simply make the BeanUtils thread safe when it's used in a private method.
And will the problem still be there if I keep the code this way but instead I call this foo() method in sevlet? If many sevlets call at the same time, would this be a multi-thread case as well?
Edit: Removed synchronized keyword since it is not neccessary, see comments below.
Instead of using the static methods in the BeanUtils class, use a private BeanUtilsBean instance (http://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/BeanUtilsBean.html). This way, you don't need to register/deregister your converters each time the method is called.
public class MyServiceImpl implements IMyService {
private final BeanUtilsBean beanUtilsBean = createBeanUtilsBean();
private static BeanUtilsBean createBeanUtilsBean() {
ConvertUtilsBean convertUtilsBean = new ConvertUtils();
convertUtilsBean.register(new MyNullConvertor(), String.class);
convertUtilsBean.register(new StringConvertorForDateType(), Date.class);
BeanUtilsBean beanUtilsBean = new BeanUtilsBean(convertUtilsBean);
return beanUtilsBean;
}
public MyObject foo(SomeObject obj) {
MyObject myobj = this.mapToMyObject(obj);
myobj.setLastUpdatedDate(new Date());
return myobj;
}
private MyObject mapToMyObject(SomeObject obj){
MyObject myojb = new MyObject();
beanUtilsBean.copyProperties(myojb , obj);
return myojb;
}
}
add a synchonized block to the sensitive portion of your code or synchronize the method:
http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

Resources