Lenient string matching with Mockito Mock - java

I have a test to verify the return of a null object if a string property of that object does not match a pre-determined value. My code is
import guru.springframework.sfgpetclinic.model.Speciality;
import guru.springframework.sfgpetclinic.repositories.SpecialtyRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
#ExtendWith(MockitoExtension.class)
class SpecialtySDJpaServiceTest {
#Mock
SpecialtyRepository specialtyRepository;
#InjectMocks
SpecialtySDJpaService service;
#Test
void testSaveLambdaNoMatch() {
// Given
final String MATCH_ME = "MATCH_ME";
Speciality speciality = new Speciality();
speciality.setDescription("Not a match");
Speciality savedSpeciality = new Speciality();
savedSpeciality.setId(1L);
// Need mock to only return on match MATCH_ME string
given(specialtyRepository.save(argThat(argument -> argument.getDescription().equals(MATCH_ME)))).willReturn(savedSpeciality);
// When
Speciality returnedSpeciality = service.save(speciality);
// Then
assertNull(returnedSpeciality);
}
// Other tests...
}
This test fails with the message
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'save' method:
specialtyRepository.save(
guru.springframework.sfgpetclinic.model.Speciality#19ae6bb
I believe the issue is that argThat() uses an exact matching scheme. I want to set the mock matching to lenient via
#Mock(lenient = true)
SpecialtyRepository specialtyRepository
But Intellij does not recognize the lenient parameter. I'm using JUnit 5 and Mockito 2.23.0

#Mock(lenient = true) was introduced in Mockito version 2.23.3.
You either have to upgrade or use the other way to write this:
lenient().when(specialtyRepository.save(argThat(argument -> argument.getDescription().equals(MATCH_ME)))).willReturn(savedSpeciality);

Related

How to obtain all ProductTypes created in my commercetools project?

I need to obtain all the ProductType that have been defined in my commercetools project because I have to use the localized value of the "name" to perform a search in a file system.
Basically I need to use the JVM SDK to extract the list of ProductTypes and traverse it.
Can someone give me some clue how to achieve it?
Thanks in advance.
Yep it is pretty feasible using the jvm sdk, here is a code snippet of how to do it
package io.sphere.sdk.deletemeplese;
import io.sphere.sdk.producttypes.ProductType;
import io.sphere.sdk.producttypes.queries.ProductTypeQuery;
import io.sphere.sdk.queries.PagedQueryResult;
import io.sphere.sdk.test.IntegrationTest;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.assertj.core.api.Assertions.assertThat;
public class SomeIntegrationTest extends IntegrationTest {
#Test
public void test(){
final int PAGE_SIZE = 500;
final long totalProductTypes = client().executeBlocking(ProductTypeQuery.of().withLimit(0)).getTotal();
List<ProductType> allProductTypes = IntStream.range(0,(int)(totalProductTypes/PAGE_SIZE) +1)
.mapToObj(i->i)
.map(i -> ProductTypeQuery.of().withLimit(500).withOffset(i*PAGE_SIZE))
.map(client()::executeBlocking)
.map(PagedQueryResult::getResults)
.flatMap(List::stream)
.collect(Collectors.toList());
assertThat(allProductTypes).hasSize((int)totalProductTypes);
}
}
I hope this answers your question.
You could use the class QueryExecutionUtils.
CompletionStage<List<ProductType>> allProductTypesStage =
QueryExecutionUtils.queryAll(client, ProductTypeQuery.of());

mocking of instance void method is working without calling 'expectLastCall' method

I just written sample test case, where I would like to mock a void instance method. I am surprised, my test case is passing without calling the expectLastCall method. I would like to know, is calling of expectLastCall is not required while mocking instance void methods?
StringUtil.java
package com.sample.util;
import com.sample.model.MethodNotImplementedException;
public class StringUtil {
public String toUpperAndRepeatStringTwice(String str) {
String upperCase = str.toUpperCase();
sendStringToLogger(upperCase);
return upperCase + upperCase;
}
public void sendStringToLogger(String str){
throw new MethodNotImplementedException();
}
}
StringUtilTest.java
package com.sample.util;
import static org.junit.Assert.assertEquals;
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({ StringUtil.class })
public class StringUtilTest {
#Test
public void toUpperAndRepeatStringTwice() {
StringUtil stringUtil = PowerMock.createPartialMock(StringUtil.class, "sendStringToLogger");
String str = "HELLO PTR";
stringUtil.sendStringToLogger(str);
//PowerMock.expectLastCall().times(1);
PowerMock.replayAll();
String result = stringUtil.toUpperAndRepeatStringTwice("hello ptr");
assertEquals(result, "HELLO PTRHELLO PTR");
}
}
expectLastCall is not required. For EasyMock and the PowerMock layer as well. So you are right.
It is used for clarity for some users. Because it makes it obvious that the method before is an expectation not some random call. But it is more a question of style than a requirement.
You also don't need the time(1) since it is the default.
BTW, the answer here is wrong and I've commented on it accordingly.

PowerMockito mocking static method fails when calling method on parameter

I'm trying to test a class which uses a calculator class with a number of static methods. I've successfully mocked another class in a similar way, but this one is proving more stubborn.
It seems that if the mocked method contains a method call on one of the passed in arguments the static method is not mocked (and the test breaks). Removing the internal call is clearly not an option. Is there something obvious I'm missing here?
Here's a condensed version which behaves the same way...
public class SmallCalculator {
public static int getLength(String string){
int length = 0;
//length = string.length(); // Uncomment this line and the mocking no longer works...
return length;
}
}
And here's the test...
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.solveit.aps.transport.model.impl.SmallCalculator;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class SmallTester {
#Test
public void smallTest(){
PowerMockito.spy(SmallCalculator.class);
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
assertEquals(5, SmallCalculator.getLength(""));
}
}
It seems there's some confusion about the question, so I've contrived a more 'realistic' example. This one adds a level of indirection, so that it doesn't appear that I'm testing the mocked method directly. The SmallCalculator class is unchanged:
public class BigCalculator {
public int getLength(){
int length = SmallCalculator.getLength("random string");
// ... other logic
return length;
}
public static void main(String... args){
new BigCalculator();
}
}
And here's the new test class...
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.solveit.aps.transport.model.impl.BigCalculator;
import com.solveit.aps.transport.model.impl.SmallCalculator;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class BigTester {
#Test
public void bigTest(){
PowerMockito.spy(SmallCalculator.class);
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
BigCalculator bigCalculator = new BigCalculator();
assertEquals(5, bigCalculator.getLength());
}
}
I've found the answer here https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/
Here's the final code which works. I've tested this approach in the original code (as well as the contrived example) and it works great. Simples...
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class BigTester {
#Test
public void bigTest(){
PowerMockito.mockStatic(SmallCalculator.class);
PowerMockito.when(SmallCalculator.getLength(any(String.class))).thenReturn(5);
BigCalculator bigCalculator = new BigCalculator();
assertEquals(5, bigCalculator.getLength());
}
}
First of all, remove that line:
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
Since you are testing the same method. You don't want to mock the method that you're testing.
Secondly, modify your annotation to:
#PrepareForTest({ SmallCalculator.class, String.class})
Lastly, add the mock for the length(); like this:
given(String.length()).willReturn(5);
I think it will do ;)
Use anyString() instead of any(String.class).
When using any(String.class) the passed argument is null, as Mockito will return the default value for the reference type, which is null. As a result you get an exception.
When using the anyString(), the passed argument will be empty string.
Note, this explains why you get an exception, however you need to review the way you test your method, as explained in other comments and answers.
If you do not want that actual method being invoked. Instead of
when(myMethodcall()).thenReturn(myResult);
use
doReturn(myResult).when(myMethodCall());
It is mocking magic and it is difficult to explain why it is actually works.
Other thing you forgot is mockStatic(SmallCalculator.class)
And you do not need PowerMockito.spy(SmallCalculator.class);

PowerMock complains of incorrect arguments even though the private method is mocked

I was trying out PowerMock, and am trying to mock a private method like so:
expectPrivate(n, "doLogin", anyString(), anyString()).andReturn(true);
That is, I want true to be returned from doLogin irrespective of the parameters passed.
The public method which delegates to this private method simply passes-on the arguments. Here is the definition of the class to be mocked:
class N {
public boolean login(String username, String password) {
return doLogin(username, password);
}
private boolean doLogin(String u, String p){
//validate login
//...
//...
return true;
}
}
And this is the test class where I am trying to invoke the mock:
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.createPartialMock;
import static org.powermock.api.easymock.PowerMock.expectPrivate;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;
import static org.mockito.Matchers.anyString;
import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
#RunWith(PowerMockRunner.class)
#PrepareForTest(N.class)
public class NodeAccessorTest {
private String username = "admin";
private String password = "asdf";
#Test
public void testMockLogin() throws Exception {
N n = createPartialMock(N.class,
"doLogin", String.class, String.class);
boolean expected = true;
expectPrivate(n, "doLogin", anyString(), anyString()).andReturn(expected);
replay(n);
boolean actual = n.login("A", "B");
verify(n);
assertEquals("Expected and actual did not match", expected, actual);
}
}
This is the failure trace:
java.lang.AssertionError:
Unexpected method call N.doLogin("A", "B"):
N.doLogin("", ""): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:91)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:124)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:185)
at com.pugmarx.mock.N.doLogin(N.java)
at com.pugmarx.mock.N.login(N.java:60)
So the mocking framework is not happy when specific Strings are passed to the public login() method, but fine when anyString is used. Ideally, I would expect that since the call to the private doLogin is mocked, this should not be the case.
What am I missing?
I had a similar issue and I think your problem can be in the Matchers anyString() passed by param to PowerMock expectPrivate method.
Based in your imports, you are using Mockito Matchers instead EasyMock Matchers: org.mockito.Matchers.anyString.
Could you try to changing the Matchers for the next: EasyMock.anyString()
import org.easymock.EasyMock;
...
expectPrivate(n, "doLogin", EasyMock.anyString(), EasyMock.anyString()).andReturn(expected);
Hope it helps.

Use of #Parameters annotation in junit 4.11-SNAPSHOT

I want to make use of the new functionality in the latest build of junit in order to name my parameterized tests
I have the following two tests written in java & scala, but the scala test generates a compiler error:
error: unknown annotation argument name: name #Parameters(name =
"{0}") def data: util.Collection[Array[AnyRef]] =
util.Arrays.asList(Array("x"), Array("y"), Array("z"))
What is the difference in implementation causing this error?
java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.fail;
#RunWith(Parameterized.class)
public class ParameterizedTest {
#Parameters(name = "{0}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[]{"x"}, new Object[]{"y"}, new Object[]{"z"});
}
#Test
public void foo() {
fail("bar");
}
}
scala
import java.util
import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized._
#RunWith(classOf[Parameterized])
class ParameterizedScalaTest {
#Test def foo() {
fail("bar")
}
}
object ParameterizedScalaTest {
#Parameters(name = "{0}") def data: util.Collection[Array[AnyRef]] = util.Arrays.asList(Array("x"), Array("y"), Array("z"))
}
Because #Parameters is defined as an inner, you seem to need to give the full name.
Try
#Parameters(Parameters.name = "{0}")
At least, that is the only significant difference I can observe in the definitions of #Parameters and #Test, and this works:
#Test(timeout = 10)
It turns out the issue here is due to junit-dep.jar being on the classpath through a transient dependency on jMock 2.4.0
Removing that fixed the compiler error, odd that this is an issue for scalac but not javac.

Categories

Resources