Mockito.donothing() also check inside the method? - java

So,I want to call the donothing() method while writing the unit test for my perticular method, what I understand of using donothing is that "it tells Mockito to do nothing when a method in a mock object is called".
But in my case when I want to tells mockito to do nothing while calling the void method, it also checks the information that written inside the method too.
Why this is happen, Is donothing method also checks inside the method or it just simply skip the testing for it.?
E.g
this is the method in that I want to call donothing:
public void deleteTemporaryRemoteBranch(final File gitFile, final String branchName) throws IOException,
GitAPIException {
final Git openedRepo = Git.open(gitFile);
//delete branch 'branchName' locally
openedRepo.branchDelete().setBranchNames(branchName).setForce(true).call();
//delete branch 'branchName' on remote 'origin'
RefSpec refSpec = new RefSpec()
.setSource(null)
.setDestination(String.format(BRANCH_HEAD_REF, branchName));
openedRepo.push().setRefSpecs(refSpec).setRemote(LambdaEnv.ORIGIN).call();
}
This is the test method :
private static final String REPO_LOCATION = "/tmp/JGitClientTest12-repo/";
private static final File REPO_FILE = new File(REPO_LOCATION);
#Test
public void clone23_happyCase2() throws Exception {
Mockito.doNothing().when(jgitAccessor).deleteTemporaryRemoteBranch(Mockito.any(),Mockito.anyString());
classUnit.deleteTemporaryRemoteBranch(REPO_FILE,Mockito.anyString());
}
When I run this method it show me the error,
java.lang.IllegalArgumentException: Invalid refspec refs/heads/
at org.eclipse.jgit.transport.RefSpec.checkValid(RefSpec.java:539)
at org.eclipse.jgit.transport.RefSpec.setDestination(RefSpec.java:337)
So why this is testing inside the deleteTemporaryRemoteBranch method, even I call donothing() in it.?
I am new to unit testing.Any suggestion!!
Also any suggestion for this issue:
java.lang.IllegalArgumentException: Invalid refspec refs/heads/
at org.eclipse.jgit.transport.RefSpec.checkValid(RefSpec.java:539)
at org.eclipse.jgit.transport.RefSpec.setDestination(RefSpec.java:337)

As you mentioned, doNothing does nothing, but in the example that you have put you are not using the mocked class, you are calling another class.
You should change
classUnit.deleteTemporaryRemoteBranch(REPO_FILE,Mockito.anyString());
for
jgitAccessor.deleteTemporaryRemoteBranch(REPO_FILE,Mockito.anyString());
In other way, that test does not make much sense since by default the mocked methods do not do
https://www.javadoc.io/doc/org.mockito/mockito-core/2.8.9/org/mockito/Mockito.html#doNothing()

Related

Unable to execute test method from mocked class

I am writing unit test for methods to find banks near my location.
I mocked the class and tried to call the methods.
But, control is not going to method to execute it.
Below is unit test case.
#Test
public void testFindBanksByGeo() {
String spatialLocation = "45.36134,14.84400";
String Address = "Test Address";
String spatialLocation2 = "18.04706,38.78501";
// 'SearchClass' is class where 'target' method resides
SearchClass searchClass = Mockito.mock(SearchClass.class);
BankEntity bank = Mockito.mock(BankEntity.class);
// 'findAddressFromGeoLocation' and 'getGeo_location' to be mocked. They are called within 'target' method
when(searchClass.findAddressFromGeoLocation(anyString())).thenReturn(Address);
when(bank.getGeo_location()).thenReturn(spatialLocation2);
// 'writeResultInJson' is void method. so needed to 'spy' 'SearchClass'
SearchClass spy = Mockito.spy(SearchClass.class);
Mockito.doNothing().when(spy).writeResultInJson(anyObject(), anyString());
//This is test target method called. **Issue is control is not going into this method**
SearchedBanksEntity searchBanksEntity = searchClass.findNearbyBanksByGeoLocation(spatialLocation, 500);
assertNull(searchBankEntity);
}
What i have tried is also calling the real method on it,
Mockito.when(searchClass.findNearbyBanksByGeoLocation(anyString(), anyDouble())).thenCallRealMethod();
This calls real method but the methods i mocked above, are executing like real one. Means 'mocked methods' are not returning what i asked them to return.
So, what wrong i am doing here ?
why method is not executing?
The method is not getting called because you are calling it on a mock. You should call the method on an actual object.
Or you could use something like this before invoking the method.
Mockito.when(searchClass.findNearbyBanksByGeoLocation(Mockito.eq(spatialLocation), Mockito.eq(500))).thenCallRealMethod();
But I think this is not the way you should write the test. You shouldn't be mocking SearchClass in the first place. Instead there would be a dependency in SearchClass which gets you the address and geo location. You should be mocking that particular dependency.
OK, let's say we have this code:
class Foo {
// has a setter
SomeThing someThing;
int bar(int a) {
return someThing.compute(a + 3);
}
}
We want to test Foo#bar(), but there's a dependency to SomeThing, we can then use a mock:
#RunWith(MockitoJunitRunner.class)
class FooTest {
#Mock // Same as "someThing = Mockito.mock(SomeThing.class)"
private SomeThing someThing,
private final Foo foo;
#Before
public void setup() throws Exception {
foo = new Foo(); // our instance of Foo we will be testing
foo.setSomeThing(someThing); // we "inject" our mocked SomeThing
}
#Test
public void testFoo() throws Exception {
when(someThing.compute(anyInt()).thenReturn(2); // we define some behavior
assertEquals(2, foo.bar(5)); // test assertion
verify(someThing).compute(7); // verify behavior.
}
}
Using a mock we are able to avoid using a real SomeThing.
Some reading:
http://www.vogella.com/tutorials/Mockito/article.html
https://github.com/mockito/mockito/wiki

Mockito with static class and method returning void

I am trying to change the implementation of a method using Mockito when the method is called, but I have two issues at the same time 1) my class is static and 2) my method returns void.
PowerMockito.doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws IOException {
DeliveryQueue.publishToQueue(testQueue, "message");
return null;
}
}).when(DeliveryQueue).publishToQueue(DeliveryQueue.REAL_QUEUE, "message");
As you can see I'm trying to tell my test that when we publish a message to the REAL_QUEUE, we should actually be sending it to the testQueue. REAL_QUEUE is static final so it's not possible to change it directly (I tried reflection without success). The problem currently is that when(DeliveryQueue) won't work as it expects a mocked object even if I've used PowerMockito.mockstatic(DeliveryQueue.class) just above. I've also tried when(DeliveryQueue.getInstance()) but it's not tagged as being the mocked object either.
Did you add #PrepareForTest(DeliveryQueue.class) at class level?
Try this: .when(DeliveryQueue.class); DeliveryQueue.publishToQueue(DeliveryQueue.REAL_QUEUE, "message");

Mockito UnfinishedStubbingException when trying to mock get class

I have a class LoggerInterceptor with an InvocationContext as parameter.
For this class I am trying to write a unit test but I am stuck on the first line:
public class LoggerInterceptor{
public method log(InvocationContext context) {
String name = invocationContext.getTarget().getClass().getName();
.....
}
My test looks like this:
#Test
public void logTest() throws Exception {
LoggerInterceptor objectToTest = new LoggerInterceptor();
InvocationContext context = Mockito.mock(InvocationContext.class);
Object target = Mockito.mock(Object.class);
Mockito.when(context.getTarget()).thenReturn(target);
MockGateway.MOCK_GET_CLASS_METHOD = true;
Mockito.doReturn(objectToTest.getClass()).when(target).getClass();
MockGateway.MOCK_GET_CLASS_METHOD = false;
objectToTest.log(context);
}
I am getting a UnfinishedStubbingException when I call the method log(context).
If I try with:
Mockito.when(target.getClass()).thenReturn(objectToTest.getClass());
I get this exception:
The method thenReturn(Class<capture#3-of ? extends Object>) in the type OngoingStubbing<Class<capture#3-of ? extends Object>> is not applicable for the arguments (Class<capture#4-of ? extends LoggerInterceptor>)
Is there any way I can pass this first line? The String that I get back is not important.
Object.getClass() is final. Final methods can't be mocked or stubbed with Mockito, because the compiler sees "final", skips the virtual method dispatch, and consequently Mockito can neither intercept calls to the method nor identify the method in doReturn, when, or verify. When you interact with Mockito later, it detects that you started stubbing but cannot detect that you finished, so it throws an UnfinishedStubbingException.
If you want to have target adjust the type or types it appears as, you'll need to change the class object passed into Mockito.mock, or add withSettings().extraInterfaces(...).

Unit testing that log message written when exception caught

Here is the code that I am working with. In this test I want to verify that the log method is being called when an exception is caught.
public class SuperClass(){
public void log()
{
do some logging;
}
}
public class ClassUnderTest extends SuperClass(){
public String methodbeingtested(Object param)
{
try
{
String a = SomeObject.
methodthatthrowsexception(param);//static method, throws JAXB/NPE
}
catch(Exception exp)
{
log("log msg",exp);//inherited method
}
}
}
public class ClassUnderTestTest {
#Test
public testmethodbeingtested(){
ClassUnderTest cut = new ClassUnderTest()
ClassUnderTest cutspy = Mockito.spy(cut);
cutspy.methodbeingtested(param);
Mockito.verify(cutspy).log("log msg", new Exception()); // exp is needed to here.
}
}
After looking at several samples, the above was the closest I could get. This testcase forces an exception. But it fails to verify the log method call as Mockito.verify requires the exact exception (exp) that is caught, which the test case does not have access to.
Is there any other way to test this scenario?
Mockito's verify method can be used with argument matchers. If you want to verify that log was called, with any Exception at all as the second argument, you can just write
verify(cutspy).log(eq("log msg"), any(Exception.class));
I've assumed that you have the right static imports for verify, eq and any.
As an aside, this test does not need PowerMock. Your line PowerMock.expectLastCall().once(); is both redundant and confusing, and should probably be removed, along with the #PrepareForTest annotation.
Instead of spying on ClassUnderTest, you should mock the logging framework, inject it into the class and then verify that the log method gets called. Id' also mock the SomeObject class and have it throw exception.
As an aside, you should really evaluate if you need to verify your log statements. Perhaps you have a valid reason to do so but typically, asserting/verifying to this extent is not required and will only make your tests brittle.

How do I share state between JUnit tests?

I have a test class extending junit.framework.TestCase with several test methods.Each method opens a HTTP connection to server and exchange request and response json strings.One method gets a response with a string called UID(similar to sessionId) which i need to use in subsequent requests to the server.
I was previously writing that string to a file and my next requests read that file for string.I am running one method at a time.Now I am trying to use that string without file operations.I maintained a hastable(because there are many UIDs to keep track of) in my test class as instance variable for the purpose , but eventually found that class is getting loaded for my each method invocation as my static block is executing everytime.This is causing the loss of those UIDs.
How do I achieve this without writing to file and reading from it?
I doubt whether my heading matches my requirement.Someone please edit it accordingly.
You will need a static variable for this because each test gets its own instance of the test class.
Use this pattern:
private static String uuid;
private void login() {
// Run this only once
if (null != uuid) return;
... talk to your server ...
uuid = responseFromServer.getUuid();
}
#Test
public void testLogin() {
login();
assertNotNull( uuid );
}
#Test
public void someOtherTest() {
login();
... test something else which needs uuid ...
}
#Test
public void testWithoutLogin() {
... usual test code ...
}
This approach makes sure that login() is called for each test that needs it, that it's tested on its own and that you can run each test independently.
JUnit will create a new instance of the class for each test. Consequently you should likely set up and store this info as static to the class, using a #BeforeClass annotated static method.
See this SO answer for more info.

Categories

Resources