Mockito mocking a function call in an if statement - java

I am trying to mock a function call to an external api that lives in an if statement. I am not able to return the value I have in .thenReturn, and I am not sure why. I have looked for answers to this on SO, but I can't seem to find anything that answers my question. Thanks a bunch for your time!
Here is my class I am testing:
#Service
public class TwilioVerifyService {
public String requestCode(String phoneNumber, String countryCode, String via) throws AuthyException
{
AuthyApiClient authyApiClient = new AuthyApiClient("<apiClient>");
Params params = new Params();
params.setAttribute("code_length", "6");
Verification verification = authyApiClient
.getPhoneVerification()
.start(phoneNumber, countryCode, via, params);
if (verification.isOk())
{
return "{ \"success\": \"Successfully sent verification code.\" }";
}
return "{ \"error\": \"Error sending code.\" }";
}
}
And here is my test:
#RunWith(MockitoJUnitRunner.class)
public class TwilioVerifyServiceTests {
#InjectMocks
TwilioVerifyService twilioVerifyService;
#Mock
Verification verification;
#Test
public void requestCodeTest_success() throws AuthyException
{
String phoneNumber = "1111111111";
String countryCode = "1";
String via = "1";
when(verification.isOk()).thenReturn(true);
String result = twilioVerifyService.requestCode(phoneNumber, countryCode, via);
System.out.println(result);
}
}
I believe I'm (or want to be) mocking out verification.isOk() to return true regardless of the inputs, but it seems to return false providing "{ "error": "Error sending code." }" instead of "{ \"success\": \"Successfully sent verification code.\" }".
Thanks again for your time!

Verification is generated from a call to methods in AuthyApiClient.
Ideally AuthyApiClient should not be instantiated in your service, but rather injected into it by the caller.
private AuthyApiClient authyApiClient;
#Autowired
public TwilioVerifyService(AuthyApiClient authyApiClient) {
this.authyApiClient = authyApiClient;
}
Then you can mock authyApiClient and pass it in to the class being tested:
TwilioVerifyService twilioVerifyService = new TwilioVerifyService(mockAuthyApiClient);
That gives you more control over the class being tested and removes the dependency it currently has on the AuthyApiClient constructor.

Related

Downcasting a CompletableFuture's object type - Java/Spring Boot

I have the following classes:
public class AccountDetail {
private String accountNumber;
private Date effectiveDate;
private String status;
// a bunch of other properties
}
public class AccountDetailWithAlerts extends AccountDetail {
private LowMediumAlerts alerts;
}
public class AccountsAndAlerts {
private List<AccountDetailWithAlerts> accounts;
private HighCustomerAccountAlerts accountAlerts;
// getters and setters
}
public class CustomerAndAccountAlerts {
private List<AlertMessage> customerAlerts;
private List<AccountAlertMessages> accountAlerts;
}
public Class CompanyResponse<T> {
#JsonInclude(JsonInclude.Include.NON_NULL)
private T response;
// other things that aren't relevant
}
I have a controller, AccountsController, that does a #GetMapping and has a ResponseEntity method:
public ResponseEntity<CompanyResponse<AccountsAndAlerts> getAccountDetails {
#RequestParam MultiValueMap<String, String> queryParms,
// some #ApiParams for client-header, end-user-id & accountNumber
String accountId = queryParms.getFirst("accountId");
// setting RestHeaders, contentType
CompanyResponse<AccountsAndAlerts> response = accountDetailService.getAccountsWithAlerts(restHeaders, accountNumber, queryParms, accountId);
return new ResponseEntity<CompanyResponse<AccountsAndAlerts>>(response, headers, HttpStatus.valueOf(response.getStatus()));
}
Here is the method in accountDetailService:
public CompanyResponse<AccountsAndAlerts> getAccountsWithAlerts(RestHeaders restHeaders, String accountNumber, MultiValueMap<String, String> queryParms, String accountId) throws... {
CompanyResponse<AccountsAndAlerts> newResponse = new CompanyResponse<AccountsAndAlerts>();
try {
CompletableFuture<List<AccountDetailWithAlerts>> accountsFuture = accountDetails.getAccounts(newResponse, restHeaders, accountNumber, queryParms);
CompletableFuture<CustomerAndAccountAlerts> alertsFuture = accountDetails.getAlerts(newResponse, restHeaders, accountId);
accountsFuture.thenAcceptBoth(alertsFuture, (s1, s2) -> newResponse.setResponse(getResponse(s1, s2))).get();
} catch {
// catch code
}
return newResponse;
}
Finally, the getAccounts method in AccountDetails:
public CompletableFuture<List<AccountDetailWithAlerts>> getAccounts(CompanyResponse<AccountsAndAlerts> newResponse, RestHeaders restHeaders, String accountNumber, MultiValueMap<String, String> queryParms) throws ... {
// this has the restTemplate and the .supplyAsync()
}
What I need to do is create a new ResponseEntityMethod in the Controller:
public ResponseEntity<CompanyResponse<AccountDetail> getCertainAccountDetails
I have put in a return of that type, and I am attempting to create a new method in the accountDetailService, getCertainAccounts().
The problem is trying to set this all up without creating a whole other CompletableFuture method with an invoke and supplyAsync() and restTemplate and such.
It appears that I still need to call getAccounts(), but then I have to somewhere along this line downcast the AccountDetailWithMessages to AccountDetail. I don't know if I can somehow downcast CompletableFuture<List<AccountDetailWithAlerts>> to CompletableFuture<List<AccountDetail>> or how to do it, or if I really need to downcast CompanyResponse<AccountsAndAlerts> or how to do that.
Can anyone help?
PS. I changed the names of everything to protect my Company's code. If you see errors in methods or names or anything, please be assured that is not an issue and is just the result of my typing things out instead of copying and pasting. The only issue is how to do the downcasting.
Thanks!
PPS. In case it wasn't clear, with my new method and code I do not want to get the alerts. I am trying to get account details only without alerts.

How to prevent Put API in your controller from XSS attacks reflected in CheckMarx scans?

I ran a CheckMarx Scan on my repository and it gave quite many potential Reflected XSS attack results. Here is the code for my controller :
#PutMapping("/calculate")
public UpdatedResponse calculateModel(
#RequestBody ModelDocument modelDocument, #RequestParam String clientFirstName,
#PathVariable String clientId, #PathVariable String clientLastName
) {
// Sanitize the parameters
modelDocument = checkForCSS(modelDocument); // NOT ACCEPTING THIS
clientId = StringEscapeUtils.escapeHtml4(clientId);
clientFirstName = StringEscapeUtils.escapeHtml4(clientFirstName);
clientLastName = StringEscapeUtils.escapeHtml4(clientLastName);
.....
}
While I was able to resolve the warnings for clientId, clientFirstName and clientLastName since they were all string variables. But how do I do it for modelDocument since it is a user defined variable in itself and further has various strings, maps etc. defined inside of it.
The method checkForCSS is defined as below but is not being recognized by the scan:
public static <T> T checkForCSS(T t) {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create();
String agendaModelStr = sanitize(gson.toJson(t));
return gson.fromJson(agendaModelStr, (Type) t.getClass());
}
public static String sanitize(String string) {
return Jsoup.clean(string, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
Any help would be appreciated. Thanks!
try this:
ESAPI.encoder().encodeForHTML(clientFirstName);
and do it for all your query params.

Test an edit function in rest with mockito - Java EE - JUnit

Currently I'm trying to work with Mockito combined with rest. I'm not sure how to test my edit method in rest with Mockito and rest. The last block of code contains the part I can't figure out atm. I haven't worked with Mockito before so all tips are welcome.
This is the functionality i want to test:
#POST
#Path("edit/{id}")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public Profile editProfile(Profile profile, #PathParam("id") Long id){
Profile updatedProfile = profileService.getProfile(id);
updatedProfile.setBiography(profile.getBiography());
updatedProfile.setLocation(profile.getLocation());
updatedProfile.setWebsite(profile.getWebsite());
updatedProfile.setAvatar(profile.getAvatar());
updatedProfile.setImage(profile.getImage());
updatedProfile.setUpdated_at(new Date());
return updatedProfile;
}
Setting up my TestClass here
Client client;
WebTarget root;
static final String PATH = "/MyApp/api/profile/";
static final String BASEURL = "http://localhost:8080" + PATH;
List<Profile> profileList = new ArrayList<Profile>();
Profile profile;
#Mock
ProfileDao profileDao;
#InjectMocks
private ProfileService profileService;
#Before
public void setUp() {
this.client = ClientBuilder.newClient();
this.root = this.client.target(BASEURL);
profile = new Profile(1L,"biography", "location" ,"website","../avatar.jpg","../image.jpg" );
for(int i = 0; i < 10; i++){
profileList.add(profile);
}
}
The Test function to edit an test: /profile/edit/1 - /profile/edit/{id}
// This part doesn't work. I'm not sure how to handle this part with mockito and rest
#Test
public void editProfileTest() {
String mediaType = MediaType.APPLICATION_JSON;
when(profileDao.find(1L)).thenReturn(new Profile(1L,"biography", "location" ,"website", "../avatar.jpg","../image.jpg"));
final Entity<Profile> entity = Entity.entity(profileService.getProfile(1L), mediaType);
Profile profileResult = this.root.path("edit/1").request().post(entity, Profile.class);
assertThat(profileResult, is(profile)); // this doesn't match
}
At first I wasn't really sure how to make the test valid but with the following piece of code I solved my problem.
Adjusted my Rest / Mockito test a little bit:
#Test
public void editProfileTest() {
String mediaType = MediaType.APPLICATION_JSON;
when(profileDao.find(2L)).thenReturn(profileList.get(0));
final Entity<Profile> entity = Entity.entity(profileService.getProfile(2L), mediaType);
Profile profileResult = this.root.path("edit/2").request().post(entity, Profile.class);
assertThat(profileResult.getId(), is(profileService.getProfile(2L).getId()));
assertThat(profileResult.getUser_id(), is(profileService.getProfile(2L).getUser_id()));
assertThat(profileResult.getAvatar(), is(profileService.getProfile(2L).getAvatar()));
assertThat(profileResult.getBiography(), is(profileService.getProfile(2L).getBiography()));
assertThat(profileResult.getLocation(), is(profileService.getProfile(2L).getLocation()));
assertThat(profileResult.getWebsite(), is(profileService.getProfile(2L).getWebsite()));
assertThat(profileResult.getImage(), is(profileService.getProfile(2L).getImage()));
}
This is testing the method on /MyApp/profile/edit/{id} only. If you have examples for an integration test or references feel free to post about it. As I'm trying to learn some more about testing in general.

Mockito Java: How to test a method which calls other class to retrieve value

I'm trying to test a method intialize transaction where the method creates a unique transaction Id. This method uses reference of other class to retrieve the properties.
After mocking the reference classes am still getting null pointer exception. when i try to test. Below is my code.
Note: JMockito
Any help appreciated
public ResponseDto initializeTransaction(RequestDTO request){
try {
String transactionId =getTransactionId(request);
ResponseDTO result = new ResponseDTO();
result.setTransactionId(transactionId);
return result;
}
}
public String getTransactionId(CreditCardGwtInitializeRequestDTO request){
StringBuffer transactionId = new StringBuffer();
String customerId = customerIdentifier.getCustomer();
UserDto userDto = user.getUserDetails(request.getKey());
String userWorkStationId =userDto.getWorkStationId();
transactionId.append(String.valueOf(System.currentTimeMillis()) + "-");
transactionId.append(userDto.getObjId()+ "-");
transactionId.append(transactionIdEncode.encode(customerId));
transactionId.append("-");
transactionId.append(transactionIdEncode.encode(userWorkStationId));
return transactionId.toString();
}
Test class
public class CreditCardGwtInitializeServiceImplTest {
private CreditCardGwtInitializeServiceImpl test;
#Mock
private CustomerIdentifier customerIdentifier;
#Mock
private UserDto userDto;
#Mock
private UserDetails user;
private CreditCardGwtInitializeRequestDTO request;
#Mock
TransactionIdCharacterEncoding transactionId;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void when_profilename_notNull_retrieveByName() throws Exception {
//test.setUser(user);
CreditCardGwtInitializeResponseDTO expected = new CreditCardGwtInitializeResponseDTO();
expected.setGatewayPassKey("");
String profileName="theName";
String connectionKey ="123456";
String custId ="custId";
request.setGatewayProfile(profileName);
request.setConnectionKey(connectionKey);
//userDto.setWorkStationId("12345");
//userDto.setObjId(12345L);
when(customerIdentifier.getCustomer()).thenReturn(custId);
when(user.getUserDetails(anyString())).thenReturn(userDto);
when(userDto.getWorkStationId()).thenReturn("RTYTYU");
when(userDto.getObjId()).thenReturn(1232324L);
when(transactionId.encode(anyString())).thenReturn("01010101");
CreditCardGwtInitializeResponseDTO response = test.initializeTransaction(request);
assertEquals(expected,response );
verifyZeroInteractions(gatewayProfileRetrievalService);
}
By adding thes lines solved my problem
MockitoAnnotations.initMocks(this);
test = new CreditCardGwtInitializeServiceImpl();
test.setUser(user);
test.setCustomerIdentifier(customerIdentifier);
test.setTransactionIdEncode(transactionId);
Here is an alternative solution that uses Mockito magic instead of manual initialization (replaces the setup method).
First override the default JUnit Runner class by the one provided by mockito (this has the same effect as MockitoAnnotations.initMocks(this)):
#RunWith(MockitoJUnitRunner.class)
public class CreditCardGwtInitializeServiceImplTest {
...
then instantiate your object right after your declare it and let mockito take care of the injection (this has the same effect as the 5 lines of your solution) :
#InjectMocks
private CreditCardGwtInitializeServiceImpl test = new CreditCardGwtInitializeServiceImpl();
...

Spring CGLIB AopProxy interferes with Jersey resource method parameter validation

Stack is Spring Boot w/ Jetty/Jersey. Here's the resource method in question:
#GET
#Path("campaignTargets")
#Produces(MediaType.APPLICATION_JSON)
#Transactional(readOnly=true)
public List<CampaignTargetOutputDTO> getCampaignTargets(
#PathParam("businessUnitId") Integer id,
#QueryParam("name") String name,
#Pattern(regexp = DATE_VALIDATION_PATTERN) #QueryParam("startDate") String startDate,
#Pattern(regexp = DATE_VALIDATION_PATTERN) #QueryParam("endDate") String endDate,
#Pattern(regexp = INTEGER_CSV_VALIDATION_PATTERN) #QueryParam("targetTypeIds") String targetTypeIds,
#Pattern(regexp = ALPHANUM_CSV_VALIDATION_PATTERN) #QueryParam("statuses") String statuses) {
return ResourceUtil.entityOr404(campaignService.getAdvertiserCampaignTargets(id, name, startDate, endDate, targetTypeIds, statuses));
}
When Jersey intercepts the call to this method to perform the validation, it doesn't (always) get this method. The reason I know this is because I have taken the advice of the Jersey documentation and created the following ValidationConfig:
#Provider
public class ValidationConfigurationContextResolver implements
ContextResolver<ValidationConfig> {
#Context
private ResourceContext resourceContext;
#Override
public ValidationConfig getContext(Class<?> type) {
final ValidationConfig config = new ValidationConfig();
config.constraintValidatorFactory(
resourceContext.getResource(InjectingConstraintValidatorFactory.class));
config.parameterNameProvider(new CustomParameterNameProvider());
return config;
}
private static class CustomParameterNameProvider extends DefaultParameterNameProvider {
private static final Pattern PROXY_CLASS_PATTERN = Pattern.compile("(.*?)\\$\\$EnhancerBySpringCGLIB\\$\\$.*$");
public CustomParameterNameProvider() {
}
#Override
public List<String> getParameterNames(Method method) {
/*
* Since we don't have a full object here, there's no good way to tell if the method we are receiving
* is from a proxy or the resource object itself. Proxy objects have a class containing the string
* $$EnhancerBySpringCGLIB$$ followed by some random digits. These proxies don't have the same annotations
* on their method params as their targets, so they can actually interfere with this parameter naming.
*/
String className = method.getDeclaringClass().getName();
Matcher m = PROXY_CLASS_PATTERN.matcher(className);
if(m.matches()) {
try {
return getParameterNames(method.getDeclaringClass().getSuperclass().
getMethod(method.getName(), method.getParameterTypes()));
} catch (Exception e) {
return super.getParameterNames(method);
}
}
Annotation[][] annotationsByParam = method.getParameterAnnotations();
List<String> paramNames = new ArrayList<>(annotationsByParam.length);
for(Annotation[] annotations : annotationsByParam) {
String name = getParamName(annotations);
if(name == null) {
name = "arg" + (paramNames.size() + 1);
}
paramNames.add(name);
}
return paramNames;
}
private String getParamName(Annotation[] annotations) {
for(Annotation annotation : annotations) {
if(annotation.annotationType() == QueryParam.class) {
return ((QueryParam) annotation).value();
} else if(annotation.annotationType() == PathParam.class) {
return ((PathParam) annotation).value();
}
}
return null;
}
}
}
My main problem with this solution is that it requires a paragraph of comment to (hopefully) prevent future confusion. Otherwise it seems to work. Without this, I get uninformative parameter names like arg1 and so on, which I'd like to avoid. Another big problem with this solution is that it relies too heavily on the implementation of Aop proxying in Spring. The pattern may change and break this code at some point in the future and I may not be here to explain this code when the comment fails to illuminate its purpose. The weirdest thing about this is that it seems to be intermittent. Sometimes the parameter names are good and sometimes they're not. Any advice is appreciated.
It turns out this happens as a result of running the server from eclipse. I haven't quite figured out why, but running the server from the command line fixes the problem. If anyone can figure out why eclipse does this and how to turn off whatever "feature" of eclipse is causing this, I will upvote/accept your answer. For now the answer is, don't run the service in eclipse.

Categories

Resources