JUnit/Mockito test failing for bizarre reason - java

I have a very simple method that I am trying to unit test:
public class MyAntTask extends org.apache.tools.ant.Task {
public void execute() {
fire();
}
public void fire() {
// Do stuff
}
}
I just want to write a unit test that confirms that calling execute() always invokes fire(), so I wrote this:
#Test
public void executeCallsFire() {
//GIVEN
MyAntTask myTask = Mockito.mock(MyAntTask.class);
// Configure the mock to throw an exception if the fire() method
// is called.
Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire();
// WHEN
try {
// Execute the execute() method.
myTask.execute();
// We should never get here; HOWEVER this is the fail() that's
// being executed by JUnit and causing the test to fail.
Assert.fail();
}
catch(Exception exc) {
// THEN
// The fire() method should have been called.
if(!exc.getMessage().equals("fired"))
Assert.fail();
}
}
I guess (and I'm by no means an expert) Mockito normally can't mock methods that return void, but this is a workaround. You basically say "wrap my object with a Mock that will always return a specific RuntimeException whenever a particular method is about to get executed". So, instead of fire() actually executing, Mockito just sees that its about to execute and throws an exception instead. Execution verified? Check.
Instead of passing, it fails at the first Assert.fail() just below the call to myTask.execute().
For the life of me, I can't figure out why. Here's the first 10-or-so lines of the enormous stack trace JUnit is giving me for the fail:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.fail(Assert.java:100)
at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
Any thoughts here, ye Mockito Gurus of StackOverflow? Thanks in advance!

Because myTask is a mock, the real object isn't called at all. To call a real object, use a spy.
You can test that a method is called using verify so there's no need for the exceptions.
public void executeCallsFire() {
MyAntTask myTask = Mockito.spy(new MyAntTask());
myTask.execute();
Mockito.verify(myTask).fire();
}
Wanting to mock the object that you're testing doesn't seem right though. It's usually better to design the test so that you're verifying calls to a separate object instead.

I see here more design issue:
why do you need one line method and both of them are public?
the mocks are for simulating dependencies and not for the class under test
if you'll make fire (quite unclear name) as private. You shouldn't test private behavior of your class

Related

How to use MockedStatic verify on static methods?

I have the following mocks for 2 different static method; UnitConversion.isCompatible() and Logging.error() that are called in my service method.
Here is my test method:
myService.demoMethod();
try (MockedStatic<UnitConversion> unitConversion= mockStatic(UnitConversion.class)) {
unitConversion.verify(never(), () -> UnitConversion.isCompatible(any()));
UnitConversion.isUnitsCompatible(any());
}
try (MockedStatic<Logging> logging = mockStatic(Logging.class)) {
logging.verify(times(1), () -> Logging.error(any()));
Logging.error(any();
}
The first method is never called while the second one is called one time when I debug. It is ok, but the test gives "Wanted but not invoked" error for the second method. I am not sure if I should call the static methods in try blocks, because I already call my service method that calls the static methods.
So, how can I verify the static method calls using MockedStatic (not powermock, etc)? SHould I call them in try blocks?
Update: I use the following approach, but it still gives "Wanted but not invoked" error even if breakpoint hit once to the static method called from the service method.
// I also try to call the service method under the test here again
demoService.create(request);
try (MockedStatic<LoggingUtils> mock = mockStatic(LoggingUtils.class)) {
// as the static method is void, no need to stub and not use "when()" in here
// I call the service method under the test
demoService.create(request);
// verify that the method is being invoked
mock.verify(times(1), () -> LoggingUtils.error(any(), any()));
}
Update-II:
demoService:
public CommandDTO create(final PurchaseRequest request) {
// code omitted
addLog();
return CommandDTO.builder().uuid(purchase.getUuid()).build();
}
private void addLog() {
LoggingUtils.error("error", null);
}
LoggingUtils:
public class LoggingUtils {
public static void error(String var1, Throwable var2) {
log.error(getString(var1), var2);
}
}
I can see a few issues in this snippet:
try (MockedStatic<UnitConversion> unitConversionMockStatic = mockStatic(UnitConversion.class)) {
unitConversionMockStatic.verify(never(), () -> UnitConversion.isCompatible(any()));
UnitConversion.isUnitsCompatible(any());
}
you verify that the method is being called before calling it
as you specified that you expect never(), this passes
you call the method with the argument matcher. This is illegal - you need to call with normal parameter.
Thus, the structure of the test should be
try (MockedStatic<UnitConversion> unitConversionMockStatic = mockStatic(UnitConversion.class)) {
// if needed, stub the static method with when
// call the static method (probably indirectly, via service under thest)
UnitConversion.isUnitsCompatible(10);
// verify that the method is being invoked
unitConversionMockStatic.verify(times(1), () -> UnitConversion.isCompatible(any()));
}
Note the usage of try-with-resources, MockStatic is no longer in effect when it is closed (which happens when you exit from the try-with-resources block). Thus, you must invoke the method under test (which calls the static method) inside of the try-with-resources block.

How to use mockito / powermockito to make an instantiated dependent class throw an exception on a specific method call

This is the code I want to test. It's pretty straight forward
class FileHandler {
public boolean deleteFiles(String path) {
// mock this to throw an exception
}
public static FileHandler instatiateNew(String location) {
// creates a FileHandler
}
}
class B {
public void action {
try {
FileHandler x = FileHandler.instantiateNew("asd");
x.deleteFiles();
} catch (Exception e) {
// untested code I want to reach
}
}
}
I now want to test method action and see how it handles x.deleteFiles() throwing an exception. I have tried doThrow, thenThrow and ran into errors (NullPointerException, probably because I stubbed the method wrongly) or the method not throwing the exception in the end.
I am also confused whether I need Powermockito or not. I will now try an approach, where I mock the whole FileHandler class. As I need to mock the static instantiation method I will need PowerMock for that. But I would prefer a less heavy handed solution. Does it exist?
my partial class mock is now:
FileHandler mockHandler = Mockito.mock(FileHandler.class)
Mockito.mock(mockHandler.deleteFiles(Mockito.anyString()).thenThrow(Exception.class);
PowerMockito.mockStatic(FileHandler.class);
PowerMockito.when(FileHandler.instantiateNew(Mockito.anyString())).thenReturn(mockHandler())
Which is still causing issues, maybe becasue FileHandler is used elsewhere and mockStatic kills all other usages.
Make sure all the necessary members are properly arranged so that the test can be exercised.
For example
RunWith(PowerMockRunner.class)
#PrepareForTest({FileHandler.class})
public class MyTestCase {
public void testdeleteFilesErrorHandling() throws Exception {
//Arrange
//instance mock
FileHandler handler = Mockito.mock(FileHandler.class);
Mockito.when(handler.deleteFiles(anyString())).thenThrow(new Exception("error message"));
//mock static call
PowerMockito.mockStatic(FileHandler.class);
Mockito.when(FileHandler.instantiateNew(anyString())).thenReturn(handler);
B subject = new B();
//Act
subject.action();
//Assert
//perform assertion
}
}
Reference: Using PowerMock with Mockito
using mockStatic was not an option for me as FileHandler was used in setup and teardown of the tests and this heavy handed approach would cause problems.
What saved me where stub and method from org.powermock.api.support.membermodification.MemberModifier.
FileHandler mock = Mockito.mock(FileHandler.class);
Mockito.when(mock.deleteFiles(anyString()))
.thenThrow(Exception.class);
stub(method(FileHandler.class, "instantiateNew", String.class)).toReturn(mock);
Note that it is necessary to prepare class FileHandler through a test class decorator and to use the PowerMockRunner. This is necessary as we are stubbing a static method on FileHandler. This is done so:
#PrepareForTest({FileHandler.class})
#RunWith(PowerMockRunner.class)
public class MyTest extends MyBaseTestClass {
#Test
public void myTest() {
// write test code from above here.
}
}

TestNG how to test exceptions in unit testing

I need to test the Exception but it gets the following error.
org.testng.TestException:
Method ContactIdentifierHelperTest.test()
[pri:0, instance:se.cambio.contactadministration.contact.helper.ContactIdentifierHelperTest#6d7b4f4c]
should have thrown an exception of type class SpiderException
Test method:
#Test(expectedExceptions = { SpiderException.class })
public void test() {
ContactData contactData = getContactData();
contactIdentifierHelper.getSpellId(contactData);
}
Method tested:
public String getSpellId(final ContactData contactData)
{
String s = null;
try
{
s = someMethod();
}
catch (SpiderException e)
{
e.printStackTrace();
}
return s;
}
Where have I gone wrong in this?
The expected behavior is that your method throws an Exception and your test fails, but it cannot never be successful (and this is correct), because you catch the exception in the body of your method.
In order to throw the exception you can simply have:
public String getSpellId(final ContactData contactData) throws SpiderException
{
return someMethod();
}
However, keep in mind that your test will be successful only if someMethod() effectively throws an exception!
Now, let me make a remark: this test does not have any sense: you are testing getSpellId but your buisiness logic is inside someMethod, and furthemore, getSpellId accept a parameter that is never used in the body ...
I suggest you change the way you think about this.
You need a repeatable, predictable way for your tested method to thrown an exception. One way to achieve that is via certain inputs.
Imagine your method looks something like this:
public String getSpellId(final ContactData contactData) throws SpiderException
{
if ( contactData == null ) throw new ArgumentException("input is null")
//some other code
}
this is something repeatable, you can always trigger the exception by passing null. You know how your code should behave, there is no uncertainty and you can test for this behaviour.
What you have however is another method call, which might fail, but you don't know how and why. This is a big no, when it comes to unit testing.
You might be better served by adding an exception test for your other method and not bother with this one.
What you really want to avoid is for your test to have too much knowledge of the code under test. You don't want to have to go through who knows how many layers in order to achieve what you want, because this leaves you with brittle tests which will need to change every time a code change happens.
So, change the way you think about the code and aim to make it testable.
Also, if you want to test for an exception, you must make sure you don't catch that exception as this will hide the actual thing.

Mock External method calls from class In Juints

I am trying to mock a call to instance of another class from my class. The issue I am seeing is that it looks like my mock object is not being replaced with the real object when I run my test. I made a simple example here to explain the case. Here I want to print tada instead of this is awsome which the method printAwsome() does by default. I have put my code in link below for reference please let me know what am I doing wrong if anything.
https://gist.github.com/anonymous/1eab366c60efb75b9075f100a67c851b
ExcelSupporTest prints this is awsome instead of tada when I try to mock optionPane.printAwsome() can someone point me to what am I doing wrong here.
To what I can infer form the question, if you are trying to mock a call to the method showMessageDialog, try mocking DefaultOptionPane as follows:
DefaultOptionPane defaultOptionPane = mock(DefaultOptionPane.class);
when(defaultOptionPane.showMessageDialog(anyObject(), anyObject(), anyString(), anyInt()))
.then(//do what you want to do here <Answer>);
What this simply means as its readable as well is whenever you make a call to showMessageDialog with any set of params you want to return something that you state as an Answer in then.
So long story short unless you pass it in as a parameter to method you cannot mock the method call.
It becomes an issue with scoping so replace this
public void testMethod() {
DefaultOptionPane optionPane = new DefaultOptionPane();
System.out.println("Entering method");
optionPane.printAwsome();
System.out.println("Exiting Method");
}
with this
public void testMethod(DefaultOptionPane optionPane) {
System.out.println("Entering method");
System.out.println(optionPane.printAwsome());
System.out.println("Exiting Method");
}
and then you can mock the optionPane

Mockito: wait for an invocation that matches arguments

I'm writing a selenium test and verifying the server behavior with mockito. Specifically, when a button is clicked, I want to make sure the page controller calls a particular method on a dependency which I've mocked.
Because it is a selenium test, I need to wait for the mock to be invoked in another thread, so I'm using mockito timeout.
verify(myMock, timeout(5000).times(1)).myMethod("expectedArg");
The trouble that I'm having is that myMethod is called many times... rather than waiting for an invocation that matches the expected arguments, timeout only waits for the first invocation.
If I use Thread.sleep(50000) rather than timeout(50000), it works as expected... but that's dirty so I'm hoping to avoid it.
How do I wait for myMethod to be invoked with the expected input?
If you are able to set a fixed number of calls to expect, it can be done with an ArgumentCaptor:
import static org.hamcrest.CoreMatchers.hasItem;
#Captor ArgumentCaptor<String> arg;
#Before
public void setUp() throws Exception {
// init the #Captor
initMocks(this);
}
#Test
public void testWithTimeoutCallOrderDoesntMatter() throws Exception {
// there must be exactly 99 calls
verify(myMock, timeout(5000).times(99)).myMethod(arg.capture());
assertThat(arg.getAllValues(), hasItem("expectedArg"));
}
Another way is to specify all the expected values to verify, but those need to be provided in the exact order that they are invoked. The difference to the above solution is that this doesn't fail even if the mock is additionally called with some non-verified arguments. In other words, no need to know the number of total invocations. Code example:
#Test
public void testWithTimeoutFollowingCallsDoNotMatter() throws Exception {
// the order until expected arg is specific
verify(callback, timeout(5000)).call("firstExpectedArg");
verify(callback, timeout(5000)).call("expectedArg");
// no need to tell more, if additional calls come after the expected arg
// verify(callback, timeout(5000)).call("randomArg");
}
This is not a super clean solution but you can do this (XX is the supposed return type here):
final CountDownLatch latch = new CountDownLatch(1);
doReturn(new Answer<XX>()
{
#Override
public XX answer(InvocationOnMock invocation)
{
latch.countDown();
return someInstanceOfXX;
}
}
).when(myMock).myMethod("expectedArg");
Then, to test if the method is called, do:
try {
assertTrue(latch.await(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
// Urgh... Failed. Deal with it and:
Thread.currentThread().interrupt();
}

Categories