Testing Private methods with Power Mockito - java

I cant seem to successfully run the test case successfully.
i have and implementation class which calls a private method as follows:
#Service
public class PermissionServiceImpl implements PermissionService {
#Autowired
private PermissionRepository permissionRepository;
#Autowired
private UserRoleRepository roleRepository;
#Override
public Set<PermissionType> getPermissions(String accessToken, String clientId) {
Map<String, List<String>> userRoles = getUserRoles(accessToken);
List<UserRole> currRole = getCurrRole(userRoles, clientId);
return getCurrentPermissions(currRole);
}
private Map<String, List<String>> getUserRoles(String accessToken) {
Map<String, List<String>> roles = new HashMap<>();
UserAccessTokenInfo userAccessTokenInfo =
SessionValidatorWithOKTA.getTokenMap().get(accessToken);
if (userAccessTokenInfo != null) {
roles = userAccessTokenInfo.getRoles();
}
return roles;
}
The above code is just a snippet. Havent given the full class due to confidentiality clause.
I have the following test case written:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PermissionServiceImpl.class)
#ExtendWith(MockitoExtension.class)
public class PermissionServiceImplTest {
#InjectMocks
PermissionService permissionService = new PermissionServiceImpl();
#Mock
PermissionRepository permissionRepository;
#Mock
UserRoleRepository roleRepository;
#Test
public void testGetPermissions() {
Set<PermissionType> permissionTypes = permissionService.getPermissions(ConstantsMock.ACCESS_TOKEN, ConstantsMock.CLIENT_ID);
assertEquals(permissionTypes, new HashSet<>());
}
#Test
public void testGetPermissions_withRoles() throws Exception {
Map<String, List<String>> roles = new HashMap();
roles.put(ConstantsMock.CLIENT_ID, new ArrayList<>(Arrays.asList("admin")));
PermissionServiceImpl mocked = PowerMockito.spy(new PermissionServiceImpl());
PowerMockito.when(mocked, method(PermissionServiceImpl.class, "getUserRoles", String.class))
.withArguments(anyString())
.thenReturn(roles);
mocked.getPermissions(ConstantsMock.ACCESS_TOKEN, ConstantsMock.CLIENT_ID)
}
}
I am getting the following error:
Misplaced or misused argument matcher detected here:
-> at
PermissionServiceImplTest.testGetPermissions_withRoles(PermissionServiceImplTest.java:51)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matches:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an
object like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be
mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
Can provide further details if needed.

Related

Mockito failing inside internal call for mocked method

I'm trying to mock the return value for a method using the when call from mockito. However, I'm new to this and I may perhaps be misunderstanding how mockito works, since the call is failing inside the method mocked when that calls another method. I thought regardless of how that method is implemented, I should be getting the return value I'm asking for? Or do I need to mock also the internals for that method? I feel that shouldn't be it.
public boolean verifyState(HttpServletRequest request, String s) {
String stateToken = getCookieByName(request, STATE_TOKEN);
String authToken = getCookieByName(request, AUTHN);
boolean isValidState = true;
if (isValidState) {
try {
log.info(getEdUserId(stateToken, authToken));
return true;
} catch (Exception e) {
ExceptionLogger.logDetailedError("CookieSessionUtils.verifyState", e);
return false;
}
} else {
return false;
}
}
public String getEdUserId(String stateToken, String authToken) throws Exception {
String edUserId;
Map<String, Object> jwtClaims;
jwtClaims = StateUtils.checkJWT(stateToken, this.stateSharedSecret); // Failing here not generating a proper jwt token
log.info("State Claims: " + jwtClaims);
edUserId = sifAuthorizationService.getEdUserIdFromAuthJWT(authToken);
return edUserId;
}
My test:
#ActiveProfiles(resolver = MyActiveProfileResolver.class)
#WebMvcTest(value = CookieSessionUtils.class, includeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {ApiOriginFilter.class, ValidationFilter.class})})
class CookieSessionUtilsTest {
#Autowired
private CookieSessionUtils cookieSessionUtils; // Service class
#Mock
private CookieSessionUtils cookieSessionUtilsMocked; // Both the method under test and the one mocked are under the same class, so trying these two annotations together.
#Mock
private HttpServletRequest request;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testVerifyState1() throws Exception {
//...Some mocks for getCookieName
UUID uuid = UUID.randomUUID();
when(cookieSessionUtils.getEdUserId(anyString(), anyString()).thenReturn(eq(String.valueOf(uuid))); // When this line runs it fails on verifyState method
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
UPDATE
Attempt using anyString() instead of eq().
Thank you.
Your test is broken in a few places.
Setting expectations on a real object
You should call Mockito.when on mocks and spies, not on System under test. Mockito normally reports it with a clear error message, but you throw a NPE from getEdUserId, so this is reported instead. The NPE stems from the fact that both eq and anyString return null, which is passed to the real method.
Invalid use of matchers
As #StefanD explained in his answer eq("anyString()") is not matching any string. It matches only one string "anyString()"
Returning a mather instead of real object
thenReturn(eq(String.valueOf(uuid)))
This is illegal position for a matcher.
Mixing Mockito and Spring annotations in a WebMvcTest
This is a common error. Mockito does not inject beans to the spring context.
From the code provided it is unclear what CookieSessionUtils is (Controller? ControllerAdvice?) and what is the correct way to test it.
Update
It seems that you are trying to replace some methods under test. A way to do it is to use a Spy.
See https://towardsdatascience.com/mocking-a-method-in-the-same-test-class-using-mockito-b8f997916109
The test written in this style:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#Spy
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
doReturn(String.valueOf(uuid)).when(cookieSessionUtils).getEdUserId(anyString(), anyString());
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
An alternative way is to call the real method, but to mock all collaborators: StateUtils and sifAuthorizationService. I would probably go with this one, if you want to test public getEdUserId.
Test written when mocking collaborators:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
when(sifAuthorizationService.getEdUserIdFromAuthJWT(cookie2.getValue())).thenReturn(String.valueOf(uuid));
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
I took the assumption that StateUtils.checkJWT does not need to be mocked
The points above are still valid and need to be resolved in either case.
Remarks
As the system under test is currently a Service, I suggest to drop WebMvcTest and test it with plain mockito instead.
Should SUT be a service? It is more typical to handle auth code in filters.
note usage of doReturn when stubbing a method on a spy.
You use mocks in more places than needed. For example Cookie is trivial to construct, there is no point in using a mock
The error is here:
when(cookieSessionUtils.getEdUserId(eq("anyString()"), eq("anyString()"))).thenReturn(eq(String.valueOf(uuid)));
It should read like
when(cookieSessionUtils.getEdUserId(anyString()), anyString()).thenReturn(uuid);
Please refer to the Mockito documentation of Argument matchers.
Because the argument matchers looking for the string "anyString()" they never match the actual parameters the method call is providing and so there is never returned the uuid you expecting.

Value passed to argumentMatchers.eq() appears null

I'm mocking a method getQuizFromQuizResponse that requires a non-null object. I tried using eq() from the ArgumentMatchers library to pass in an existing object I initialized. When I debug SecurityServiceTest in my IDE, eq(quizResponse) appears exactly how I intend it to. When I reach a breakpoint in the method I'm mocking, getQuizFromQuizResponse(), quizResponse then appears as null.
Why doesn't eq() keep the value I defined when mocking?
For further context:
[OUTDATED] the class of the method I am attempting to mock, QuizMapper, is a Spy. I mention this because I feel this could be why I'm having this issue?
[OUTDATED] The reason I have QuizMapper as a Spy is because we did not create this class to be a bean since it's purpose is to simply map from DTO to another... so it isn't a Service.
[OUTDATED] Since QuizMapper isn't a bean I couldn't autowire it or inject it into SecurityService and attempting to make it a #Mock would have mockito giving me error like so: "Strict stubbing argument mismatch"
I now have QuizMapper as a #Mock because I realized that in verifyUser() I'm calling on a builder which is causing the argument mismatch to have some initialized data which I believe goes against stubbing?
Here's the error:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'checkIdentity' method:
feignClient.checkIdentity(
0L,
null,
Verification(type=Initiate, settings=Settings(mode=null,
reference=Reference1, locale=en_US, venue=online), persons=.
[Person(name=null, addresses=[], ssn=null, phones=null,
emails=null, context=primary, Id=Id)], answers=null)
);
-> at com.*.Service.verifyUser(SecurityService.java:39)
- has following stubbing(s) with different arguments:
1. feignClient.checkIdentity(
0L,
null,
null
);
Here's my code:
#ExtendWith(MockitoExtension.class)
class SecurityServiceTest {
#InjectMocks
private SecurityService securityService;
#Spy
private FeignClient feignClient;
#Spy
private QuizMapper quizMapper;
#Test
void testVerifyUserReturnsQuiz() throws ProviderException {
String id = "Id";
String mode = "test";
Quiz expectedQuiz = new Quiz();
expectedQuiz.setId("quizId");
Verification verification = new VerificationBuilder()
.setType(VerificationBuilder.TYPE)
.setMode(mode)
.setId(id)
.build();
QuizResponse quizResponse = new QuizResponse();
quizResponse.setProducts(new ProductTestUtil().getProductList());
given(
feignClient.checkIdentity(any(Long.class), any(String.class), eq(verification))
).willReturn(singleQuizResponse);
given(
quizMapper.getQuizFromQuizResponse(eq(quizResponse))
).willReturn(expectedQuiz);
Quiz actualQuiz = securityService.verifyUser(id);
assertEquals(actualQuiz, expectedQuiz);
}
}
Here is the class and function I am trying to invoke in my unit test
#Slf4j
#Service
public class SecurityService {
private final FeignClient feignClient;
#Value(“${mode}")
private String settingsMode;
#Value("${accountId}")
private long accountId;
#Value("${workflowName}")
private String workflowName;
public SecurityService(FeignCleint feignClient) {
this.feignClient = feignClient;
}
public Quiz verifyUser(String lexId) throws ProviderException {
QuizMapper quizMapper = new QuizMapper();
Verification user = new VerificationBuilder()
.setType(VerificationBuilder.TYPE)
.setMode(mode)
.setId(Id)
.build();
logger.info("Verification POST request: {}", user);
QuizResponse response = feignClient.checkIdentity(accountId, workflowName, user);
logger.info("QuizResponse POST response: {}", response);
return quizMapper.getQuizFromQuizResponse(response);
}
}

How to mock Autowired constructor dependency in groovy spock

I have a class for which i am writing groovy test case. This class has constructor autowiring and calls another method to initialise the fields.:
#Service
public class ServiceA {
private final PrincipalDao principalDao;
#Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao=principalDao;
this.serviceMap = getMap();
}
private Map<> getMap() {
final List<ClassA> classAList = principalDao.findAll(); //this line returns null
}
}
this line final List<ClassA> classAList = principalDao.findAll(); returns null and I cant mock it in groovy like following:
principalDao.findAll() >> list
because its called even before my above line is called in groovy test case
Without seeing you unit test, it's hard to tell what the issue is, but a common misconception I run into sometimes is the timing of the mock.
Here's a sample code elaborating what I mean. Since parts of the code missing from your question, going to assume some parts of it, but I'm sure it explains the point I'm making and hopefully should help you out in finding an answer:
Service class:
#Service
public class ServiceA{
private final PrincipalDao principalDao;
private final Map<String, String> serviceMap;
#Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao = principalDao;
this.serviceMap = getMap();
}
private Map<String, String> getMap(){
final HashMap<String, String> stringStringHashMap = new HashMap<String, String>();
stringStringHashMap.put("hello", principalDao.khello());
return stringStringHashMap;
}
public String printServiceMap() {
return serviceMap.get("hello");
}
}
class ServiceATest extends Specification {
def "some test"() {
given:
PrincipalDao principalDao = Mock()
principalDao.khello() >> "khello" // this is the key here. Mocking is happening before instantiation of ServiceA
ServiceA someService = new ServiceA(principalDao)
expect:
"khello" == someService.printServiceMap()
}
}
This unit test passes successfully. The point here is the timing of the mocking. principalDao.khello() >> "khello" happens before new ServiceA(principalDao).
If you don't need to modify serviceMap per unit test, you can also do this so you don't have to define it per unit test:
class ServiceATest extends Specification {
#Shared
PrincipalDao principalDao = Mock()
ServiceA someService = new ServiceA(principalDao)
def setupSpec() {
principalDao.khello() >> "khello"
}
def "some test"() {
expect:
"khello" == someService.printServiceMap()
}
}

Mockito.when giving InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here

Following is the Test Class
#RunWith(MockitoJUnitRunner.class)
public class AuditServiceClientTest {
private MockMvc mockMvc;
#Mock
private RestTemplate restTemplate;
#Mock
AuditServiceClient auditServiceClient;
#Mock
ICommonDataService iCommonDataService;
private AuditServiceResponse auditServiceResponse;
private AuditServiceLog auditServiceLog;
private HttpEntity<AuditServiceLog> request;
#Before
public void setUp() throws Exception {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("X-AGS-Client-Name", "test");
headers.add("X-AGS-Group-Name", "test");
headers.add("Content-Type", "application/json");
auditServiceClient = new AuditServiceClientImpl();
iCommonDataService = new CommonDataService();
auditServiceLog = new AuditServiceLog();
request = new HttpEntity<AuditServiceLog>(auditServiceLog, headers);
auditServiceResponse = new AuditServiceResponse();
auditServiceResponse.setStatus(String.valueOf(200));
auditServiceResponse.setTimestamp("1990-01-01 00:00:01");
auditServiceResponse.setDescription("Description");
Mockito.when(restTemplate.postForObject(Mockito.anyString(), any(HttpEntity.class), ArgumentMatchers.eq(AuditServiceResponse.class)))
.thenReturn(auditServiceResponse);
String a = "test";
ArrayList<Integer> mockedList = new ArrayList<Integer>();
Mockito.when(iCommonDataService.getEnvValue(Mockito.anyInt(), Mockito.anyInt(), Mockito.anyString()))
.thenReturn(a);
}
#Test
public void postTest() {
AuditServiceResponse response = null;
try {
response = auditServiceClient.post("endpoint", auditServiceLog, true);
} catch (Exception e) {
e.printStackTrace();
}
Assert.assertTrue(Integer.parseInt(response.getStatus() )== 200);
}
}
I am getting
InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here
in the setUp() method on the following line:
Mockito.when(iCommonDataService.getEnvValue(Mockito.anyInt(), Mockito.anyInt(), Mockito.anyString()))
.thenReturn(a);
Following is the error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at com.auditService.test.AuditServiceClientTest.setUp(AuditServiceClientTest.java:72)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last
matcher is returning an object like any() but the stubbed method
signature expect a primitive argument, in this case, use primitive
alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with
methods that cannot be mocked. Following methods cannot be
stubbed/verified: final/private/equals()/hashCode(). Mocking methods
declared on non-public parent classes is not supported.
There are a lot of articles on this error around but none of them worked for me. Is there any issue with Mockito.anyInt() because Mockito.anyString() is being used in the previous line and that works fine. Any help is appreciated.
Look carefully at your test code:
iCommonDataService = new CommonDataService();
...
Mockito.when(iCommonDataService.getEnvValue(Mockito.anyInt(), Mockito.anyInt(), Mockito.anyString()))
.thenReturn(a);
You're mocking a method of an object wich is not a mock, that's the cause of the exception.
Since you already have a mock of this class declared wih #Mock annotation, you can simply remove this line iCommonDataService = new CommonDataService();. Another way could be providing a mock manually using Mockito.mock(CommonDataService.class).
But, if you want to mock a method of the original object, you should use Mockito.spy() instead.
I used #RunWith(SpringRunner.class)instead of #RunWith(MockitoJUnitRunner.class) which helps to resolve this issue.

Mockito default behaviour and custom behaviour with methods with identical return types

Supossing I have the following code to test UserController by mocking UserService (where UserController has a reference to UserService):
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
...
public class UserControllerTest {
private final List<User> users1 = new ArrayList<>();
private final List<User> users2 = new ArrayList<>();
#Before
public void initUsers() {
User user = new User();
user.setId(1L);
users1.add(user);
User user = new User();
user.setId(2L);
users2.add(user);
}
#Test
public void testFindAlls() throws Exception {
UserService userService = mock(UserService.class); //line1
when(userService.findAll1()).thenReturn(users1); //line2
when(userService.findAll2()).thenReturn(users2); //line3
UserController userController = new UserController();
ReflectionTestUtils.setField(userController, "userService", userService);
List<User> users3 = userController.findAll1(); //line4
List<User> users4 = userController.findAll2(); //line5
...
}
}
I have the following doubts:
When the line1 is reached, what would be the default behaviour for userService.findAll1() and userService.findAll2()?
When the line3 is reached, as userService.findAll1() and userService.findAll2() return the same result type (List<User>). Will the line3 override the behaviour defined in line2? I mean, will userService.findAll1() return users2 instead of users1?
I mean, the when method signature is public static <T> OngoingStubbing<T> when(T methodCall) so T in the example would be an element of type List<User> with the value probably to null. So, how the when method is able to determine that different calls are passed as arguments?
1.
When you mock something all methods - that have a return type - would just return null by default (or equivalents in case of primitives). Since the mock has no implementation on its own, a call to the method is doing nothing (basically it handles like an empty method).
2.
Why would that be? You map different return values to different methods, there is no possibility of overriding something.
Edit3:
I just removed my previous try to expalin this. The content of the link is better than anything I can come up with. So it's not easy to understand.
How does mockito when() invocation work?
On another note:
You might not need to use Reflections to put the mock into your object. Check out #InjectMocks & #Mock. So wheter you can use them (or how to use them) depends on your JUnit and Mockito version.
(How to use Mockito with JUnit5)

Categories