Mock constructor of a class - mockito

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

Related

Mockito.mockConstruction provides null logger in the tested class

I want to test the method Utility#fromJson. In order to do that I need to mock the LoggerBean constructor which has some JNDI code in it.:
public class Utility {
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
private static ObjectMapper mapper = new ObjectMapper();
public static <T> T fromJson(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (IOException e) {
//during test log is null here
log.error("json deserialization failed", e);
}
return null;
}
}
In the following test class I can mock the constructor with mockito and want that mocked Logger should be present in the Utility class. However the log in the Utility class is null during the test.
class UtilityTest {
#Test
void testFromJson() throws Exception {
// mocking constructor
try (MockedConstruction<LoggerBean> mocked = Mockito.mockConstruction(LoggerBean.class, (mock, context) -> {
// further stubbings ...
when(mock.getLogger(getClass())).thenReturn(Logger.getLogger(getClass()));
})) {
// the logger here works
// Logger logger = Logger.getLogger(getClass());
//logger.info("-----------------");
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
I am using mockito-inline version 3.11.2.
Please suggest how to get the mocked log in the Utility class.
A distinct non-answer: don't even try.
If you really absolutely want a static method, then why not create a small utility class that does the same thing in a non static way (where you then can use the ctor of that class to insert your dependencies). And then maybe and keep a static instance of that class for your static method.
Remember that static comes with a lot of disadvantages. Especially in this case: if you can't test this static utility code without doing all this extra work, then you just introduced something that will interfere with unit testing any of the code that is going to use the static method.
In other words: you created hard to test code. Now you are facing the consequences of that, and your answer is to reach for the biggest hammer in the toolbox. But hammering a screw into the wall, yes that is possible, but is rarely a good idea. Instead you pick up a nail, or you go with the screw, but a screwdriver.
The real solution: step back, and remember to only only only ever use static for production code when doing so does not interfere with your ability to do proper, decent, simple unit testing.
Other readers: do not see this answer as discouragement to give the correct technical answer please!
So I finally realized that there is no need to mock the constructor of LoggerBean so that the following works:
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
So Mockito.mock(LoggerBean.class) already skips the call to the constructor.
class UtilityTest {
private static Logger log = LoggerBean.getLoggerBean().getLogger(UtilityTest.class);
#Test
void testFromJson() throws Exception {
try (MockedStatic<LoggerBean> mockedStaticLoggerBean = Mockito.mockStatic(LoggerBean.class)) {
LoggerBean loggerBeanMocked = Mockito.mock(LoggerBean.class);
when(loggerBeanMocked.getLogger(Utility.class)).thenReturn(pp);
mockedStaticLoggerBean.when(() -> LoggerBean.getLoggerBean()).thenReturn(loggerBeanMocked);
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
Now the Utility#fromJson will get the logger from UtilityTest class.

Mockito Method calls

I have a DAO implementation class :
public class DataPollingDAOImpl implements DataPollingDAO {
public List<String> getInfo(String id,String columnName)
{
// some code which calls the database and retrieves data.
}
}
I have written a mockito test case as follows-
public class connection{
#Mock private DataPollingDAOImpl myDao;
#Test public void test() {
when(myDao.getInfo("520", "Hole"));
}
}
I created a mock database connection as well. However what shall I do to print success on the console to show a success case after calling myDao.getInfo() in test method?
If you are mocking using #Mock then I suppose you want your mock to return a value, you specify how to return the value by:
when(myDao.getInfo(anyString(), anyString()).thenReturn(Arrays.asList("yourReturnValue"));
If you want to see if you have called your Mock, then normally #Spy is used and you write:
Mockito.verify(myDao).getInfo(anyString(),anyString());
And I do recommend you to use interfaces (as DataPollingDAO) and not implementations (DataPollingDAOImpl)

JukitoRunner, bind mock of final class

How to bind mock of final class in Jukito ?
For example :
public final class SomeFinalClass(){
public SomeFinalClass(String someString){
}
}
//Testing class
#Runwith(JukitoRunner.class)
public class TestingClass(){
#Inject
private SomeFinalClass someFinalClassMock;
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
// bind(SomeClient.class).in(TestSingleton.class);
}
#Provides
public SomeFinalClass getSomkeFinalClass() {
return Mokito.mock(SomeFinalClass.class); //throws error
}
}
}
Is there a way i can use PowerMockito with JukitoRunner ?
You can mock a final class if you're using Mockito 2. From Mockito 2 Wiki:
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line: mock-maker-inline.
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

Is there any way to mock field of Class

Here's my case, I have a class A which has one member field b. And I want to test and in unit test, I mocked A and also need to call method f() which will invoke b's f(). But the b variable in mocked A is null, so will throw NPE, and I have no get/set method for b, so is there any way to mock b ? THanks
public static class B{
public void f() {
}
}
public static class A {
B b;
public void f() {
b.f();
}
}
If you want to mock out the b property of A in a test, you've given the b property default (package-private) access, so as long as your test is in the same package you could replace the b property directly.
#Test
public void testB() {
A underTest = new A();
B mockedB = Mockito.mock(B.class);
underTest.b = mockedB;
underTest.f();
Mockito.verify(mockedB).f();
}
As an aside, I personally dislike using package-private access to mess around with member properties for tests, and instead would recommend a dependency injection framework like Guice or Spring DI for constructor injection.
However you've described that you've mocked out A, I'd have thought if this was the case the f() method of A would do nothing - you wouldn't get a null pointer exception as the call to the mock will replace the real b property and just be a void method that does nothing. Please can you provide more details if this is the case?

Mocking methods of local scope objects with Mockito

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.

Resources