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.
Related
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.
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.
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);
}
}
I am trying to mock this method with postForEntity call -
public AuthorizeClient(RestTemplateBuilder builder, Config config) {
this.grantedUrl = config.grantedUrl();
this.restTemplate = HttpClientHelper.getRestTemplate(builder, authorizationConfig);
}
private final RestTemplate restTemplate;
private String grantedUrl;
public List<Permission> getPermissions(
PermissionsRequest permissionsRequest) {
try {
var headers = new HttpHeaders();
var request = new HttpEntity<PermissionsRequest>(permissionsRequest, headers);
var permissions = restTemplate.postForEntity(grantedUrl, request, Permission[].class);
return Arrays.asList(permissions.getBody());
} catch (HttpClientErrorException err) {
logger.error(err);
throw err;
}
}
Here is my test case -
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
Config config = new Config();
#InjectMocks
AuthorizeClient authorizeClient = new AuthorizeClient(restTemplateBuilder, config);
#Mock
private RestTemplate restTemplate;
PermissionsRequest permissionsRequest;
ResponseEntity<Permission[]> expGrantedPermissions;
#Test
public void testAuthorizationPermissions() {
when(restTemplate.postForEntity(anyString(), any(), eq(Permission[].class))).thenReturn(expGrantedPermissions);
var res = authorizeClient.getAllGrantedPermissions(permissionsRequest);
assertNotNull(res);
}
I'm getting this error. Looks like mock is not created properly ..
java.lang.IllegalArgumentException: URI is not absolute
At this line -
var res = authorizeClient.getPermissions(permissionsRequest);
My AuthorizeClient is constructed like above..
Please suggest what am I missing.
Thanks in advance
From your example code I don't see a relation between your restTemplate mock and the AuthorizeClient class.
The problem is that your restTemplate field in your object is final. In this case - even so the #InjectMocks generally works with the new constructor - injection of the mock does not happen.
You might want to add the full stacktrace, but I would assume that config.grantedUrl() does not return a valid url.
I assume grantedUrl is a String. In that case you define behaviour for the wrong method. There is only a 4-param version of postForEntity, so you'll need to define the mock for that using Mockito.<Object>any() for the varargs parameter.
To fix this: You might want to mock the RestTemplateBuilder and define behaviour for the methods that are used by HttpClientHelper.getRestTemplate.
You might also want to consider using PowerMockito to mock the static method directly.
Alternatively you could refactor your code to pass the RestTemplate directly to the constructor instead of passing the builder. At least in your example the builder does not seem to be used for anything else within the class, so I would consider it a removable dependency.
Also using Constructor injection is considered the way to go by many.
I assume PermissionsRequest andPermission` are your classes, so I can't really test this specific case, but basically this should work:
Note that I assume a changed constructor for AuthorizeClient that accepts both config and restTemplate. Instead of using the annotation I setup the mock manually, because you used a real Config object in your example. If mocking both is an option, you can still use the #InjectMocks annotation.
#RunWith(MockitoJUnitRunner.class)
public class RestTemplateTest {
Config config = new Config();
#Mock
private RestTemplate restTemplate;
PermissionsRequest permissionsRequest;
ResponseEntity<Permission[]> expGrantedPermissions;
#Test
public void testAuthorizationPermissions() {
// init permissionsRequest and expGrantedPermissions, if you haven't done that
AuthorizeClient authorizeClient = new AuthorizeClient(config, restTemplate);
Mockito.when(restTemplate.postForEntity(Mockito.anyString(), Mockito.any(), Mockito.eq(Permission[].class), Mockito.<Object>any())).thenReturn(expGrantedPermissions);
List<Permission> res = authorizeClient.getAllGrantedPermissions(permissionsRequest);
assertNotNull(res);
}
}
Ps.:
For a standalone example of a different method on restTemplate you can check my answer here. This at least can help you verify that you mock the correct method.
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)