How to use PowerMockito to verify super method is called - mockito

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.

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());
}
}

Mockito, channel output of void function to System.out?

I have this logging class in my legacy application,
I am trying to Mock it for testing and output all messages from "WriteLog" method to System.out
This is the class
public abstract class LoggingServicesWorker {
public abstract void WriteLog(ELogLevel arg0, int arg1,String arg2,String arg3);
}
This is what I did so far,
I am not sure how to write to System.out
Also How to tell the first argument to have any enum type (ELogLevel)?
LoggingServicesWorker logger = mock(LoggingServicesWorker.class);
Mockito.doNothing().when(logger).WriteLog(ELogLevel.DEBUG,anyInt(),anyString(),Mockito.eq(anyString()));
You can use Mockito#doAnswer for executing side-effects:
doAnswer((invocation -> {
System.out.println(Arrays.toString(invocation.getArguments()));
return null;
}))
.when(worker)
.WriteLog(any(ELogLevel.class), anyInt(), anyString(), anyString());
Standalone class with the default behavior for return values (and usable with Java 7):
class PrintArgsToStdoutAnswer implements Answer<Object> {
private final ReturnsEmptyValues defaultReturn = new ReturnsEmptyValues();
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
System.out.println(Arrays.toString(invocation.getArguments()));
return defaultReturn.answer(invocation);
}
}
...and used in the test method:
doAnswer(new PrintArgsToStdoutAnswer())...

How do you Unit Test a ForeachWriter implementation?

I've been trying to setup some unit tests to verify the logic in a ForeachWriter custom implementation but am running into a bit of mocking / duplication trouble.
I'd like to Mock an injected dependency in the ForeachWriter, but my mocks seem to be duplicated during execution. Originally I thought the mocked dependencies weren't getting called, but during debug inspection I've found that multiple versions of them seem to exist (based on hashCode).
Here's some quick sample code of what I've been trying to do:
//Class I'd like to test
public class TestForeachSink extends ForeachWriter<String> {
#Inject
SomeDependency dep;
public TestForeachSink(SomeDependency dep) {
this.dep = dep;
}
#Override
public boolean open(long partitionId, long version) {
dep.doSomethingStartupRelatedOrThrow();
return true;
}
#Override
public void process(String value) {
dep.processSomething(value);
}
#Override
public void close(Throwable errorOrNull) {
dep.closeConnections();
}
}
//Testing Class
public class TestForeachSinkTests {
#Mock SomeDependency _dep;
TestForeachSink target;
#BeforeEach
public void init() {
_dep = mock(SomeDependency.class, withSettings().serializable());
target = new TestForeachSink(_dep);
}
#Test
pubic void shouldVerifyDependencyInteractions() {
//setup stream, add data to it
stream.toDS().writeStream().foreach(target).start().processAllAvailable();
//VERIFY INTERACTIONS WITH MOCK HERE
}
}
The added data runs through the stream as expected but it seems like the mock I've passed in of SomeDependency is replaced during execution with a copy. I think that makes sense if the execution is running as though it were performing on a separate worker, but I'd still like to be able to test the ForeachWriter.
Is anyone else testing this part of the code? I haven't come across any other tests for ForeachSink custom implementations but direction on moving forward would be very appreciated!

How to mock System.getenv() in JUnit [Powermock + Parameterized]

How to mock "System.getenv("...")" in JUnit.
Currently I am doing:
#RunWith(Parameterized.class)
#PowerMockRunnerDelegate(PowerMockRunner.class)
#PrepareForTest(System.class)
public class TestClass extends BaseTest {
public TestClass(String testCase) {
this.testCase = testCase;
}
#Before
#Override
public final void initTable() throws Throwable {
super.initTable();
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("ENV_VAR1")).thenReturn("1234");
}
...
}
I am using both PowerMock and Parameterizedrunner.
I am getting below exception for line:
PowerMockito.when(System.getenv("ENV_VAR1")).thenReturn("1234");
Exception:
org.mockito.exceptions.base.MockitoException:
'afterPropertiesSet' is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
***
Use the #RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
Use the #PrepareForTest({ClassThatCallsTheSystemClass.class}) annotation at the class-level of the test case.
Example with using EasyMock
public class SystemClassUser {
public String performEncode() throws UnsupportedEncodingException {
return URLEncoder.encode("string", "enc");
}
}
And test
#RunWith(PowerMockRunner.class)
#PrepareForTest( { SystemClassUser.class })
public class SystemClassUserTest {
#Test
public void assertThatMockingOfNonFinalSystemClassesWorks() throws Exception {
mockStatic(URLEncoder.class);
expect(URLEncoder.encode("string", "enc")).andReturn("something");
replayAll();
assertEquals("something", new SystemClassUser().performEncode());
verifyAll();
}
}
From:
https://github.com/powermock/powermock/wiki/MockSystem
So, you should add a class that uses the System.getenv, not the System class to #PrepareForTest.
This post explains why it should be done in such way.
Also, I'd like to recommend to use the System Rules library for your case. It has a good way to stub environment variables. PowerMock modifies a class byte code, so it makes test slowly. And even if it not modify a class it at least read class from disk.

Powermock to mock instance methods called from other executing methods

In this code, i have mocked the one of the ValidateHandlerSoapClient class method which is instantiated and called this method (soapClientSpy.processSoapRequestRespons) in validateMsisdnHandlerIRSpy.validate().So soapClientSpy.processSoapRequestResponse is not working , instead the real method is called.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ValidateMsisdnHandler.class,ValidateHandlerSoapClient.class})
public class Demo {
MessageControl messageControl=PowerMockito.mock(MessageControl.class);
Validate validate=PowerMockito.mock(Validate.class);
ValidateMsisdnHandlerIR validateMsisdnHandlerIRSpy = PowerMockito.spy(new ValidateMsisdnHandlerIR());
ValidateHandlerSoapClient soapClientSpy = PowerMockito.spy( new ValidateHandlerSoapClient());
#Before
public void initialize() throws Exception
{
PowerMockito.when(validate.getAccountId()).thenReturn("0879221485");
PowerMockito.doReturn(true).when(validateMsisdnHandlerIRSpy, "isPrePaid",anyString());
MemberModifier.field( ValidateMsisdnHandlerIR.class, "endDate").set(
validateMsisdnHandlerIRSpy, "10-FEB-2015");
PowerMockito.when(soapClientSpy.processSoapRequestResponse(anyString())).thenReturn(true);
PowerMockito.whenNew(ValidateHandlerSoapClient.class).withNoArguments().thenReturn(soapClientSpy);
}
#Test
public void testValidateMsisdn_Cr6_Roverprempay_Not_Roverpayg() throws Exception{
Response response = validateMsisdnHandlerIRSpy.validate(validate,messageControl);
}
Replace
ValidateHandlerSoapClient soapClientSpy = PowerMockito.spy( new ValidateHandlerSoapClient())
with
ValidateHandlerSoapClient soapClientMock = PowerMockito.mock(ValidateHandlerSoapClient.class)
A spy by default just calls the methods of the underlying regular class. What you want to do is (presumably) nothing when the methods of the soap client are called.
Then of course you will need to make also change:
PowerMockito.whenNew(ValidateHandlerSoapClient.class).withNoArguments().thenReturn(soapClientMock);

Resources