I have these two functions in my userServiceImpl class. I want to write their test cases. I am completely new to this so cannot figure out how to write the jUnit test cases.
public UserDto updateUser(String userId, UserDto user) {
UserEntity userEntity = this.userRepository.findByUserId(userId);
if (userEntity == null)
throw new UsernameNotFoundException("User with ID: " + userId + " not found");
userEntity.setName(user.getName());
userEntity.setCity(user.getCity());
userEntity.setAddress(user.getAddress());
userEntity.setPhoneNumber(user.getPhoneNumber());
UserEntity updatedUserDetails = userRepository.save(userEntity);
return new ModelMapper().map(updatedUserDetails, UserDto.class);
}
#Override
public List<UserDto> getUsers(int page, int limit) {
List<UserDto> returnValue = new ArrayList<>();
Pageable pageableRequest = PageRequest.of(page, limit);
Page<UserEntity> usersPage = this.userRepository.findAll(pageableRequest);
List<UserEntity> users = usersPage.getContent();
//loop on list of users and create new userdto for each user
for (UserEntity userEntity : users) {
UserDto userDto = new UserDto();
BeanUtils.copyProperties(userEntity, userDto);
returnValue.add(userDto);
}
return returnValue;
}
I tried writing the test case for updateUser but it failed
testUpdateUser
final void testUpdateUser() {
when(userRepository.save(any(UserEntity.class))).thenReturn(userEntity);
UserDto userDto = new UserDto();
UserDto storedDetails = userService.updateUser("edsd3445tcd", userDto);
assertNotNull(storedDetails);
}
Please help me with these two test cases.
As discussed in the comments: The method findByUserId of the Mock is called but the call is not part of the teaching. The Mock will return null and therefore we get an UsernameNotFoundException.
Solution: add the missing when(userRepository.findByUserId(...))...;
I also suggest to use an ArgumentCaptor to be able to add some assertions.
Without the capture, you won't see, if the changes will be saved.
Variable userEntity seems to be a member variable. I would rather use two local variables, one to represent the state at the first teaching and one to represent the state at the second teaching.
final void testUpdateUser() {
var id = "edsd3445tcd";
var userEntityBeforeChange = new UserEntity();
userEntityBeforeChange.setId(id);
userEntityBeforeChange.setName("Old Name");
// ... set more attributes ...
var userEntityAfterChange = new UserEntity();
userEntityAfterChange.setId(id);
userEntityAfterChange.setName("Changed Name");
// ... set more attributes ...
when(userRepository.findByUserId(id)).thenReturn(userEntityBeforeChange);
ArgumentCaptor<UserEntity> argument = ArgumentCaptor.forClass(UserEntity.class);
when(userRepository.save(argument.capture())).thenReturn(userEntityAfterChange);
UserDto userDto = new UserDto();
userDto.setName("New Name");
// ... set more attributes ...
UserDto storedDetails = userService.updateUser(id, userDto);
assertEquals(userDto.getName(), argument.getValue().getName());
assertNotNull(storedDetails);
assertEquals(userEntityAfterChange.getName(), storedDetails.getName());
// ... assertions for other attributes ...
}
Testing getUsers works in the same way: Teach the mock that there will be a call of findAll, call getUsers and finish with some assertions.
Related
I am new to reactive and not able to get around this.
I have following Dtos:
public class User {
int id;
Map<String, Car> carsMap;
}
public class Car {
String carName;
}
// Response object
public class VehiclesInfo {
List<String> vehicleName;
}
From database I am getting Mono<User> when querying by userId.
And I have to return Mono<VehiclesInfo>.
So, I have to map the carsMap received from Mono<User> into List i.e. List of carName and set that into VehiclesInfo and return that as Mono i.e. Mono<VehiclesInfo>.
I am doing it like below. Please let me know how this can be done without blocking.
// userMono is returned by database query
Mono<User> userMono = getUserInfoById(userId);
Optional<User> userOptional = userMono.blockOptional();
if (userOptional.isPresent()) {
User user1 = userOptional.get();
Flux<Car> carFlux = Flux.fromIterable(user1.getCarsMap().keySet())
.flatMap(i -> {
final Car c = new Car();
c.setCarName(i);
return Mono.just(c);
});
carFlux.subscribe(c -> System.out.println(c.getCarName()));
}
I'm trying to implement PayPal's API, but as this is the first time im using it, I get some errors.
This is the code:
Controller
#PostMapping("/checkout/paypal")
public String checkout_paypal(#RequestParam(value = "id") Integer id) throws Exception {
Order order = orderServices.findOrderById(id);
try {
Payment payment = service.createPayment(order.getTotalPrice().doubleValue(), "EUR", "PAYPAL",
"ORDER", "Order id:"+order.getId(), "http://localhost:4200/checkout?id="+order.getId(),
"http://localhost:4200/checkout?id="+order.getId());
for(Links link:payment.getLinks()) {
if(link.getRel().equals("approval_url")) {
return "redirect:"+link.getHref();
}
}
} catch (PayPalRESTException e) {
e.printStackTrace();
}
System.out.println("Success");
return "Success";
}
#GetMapping("/successPaymentPaypal")
public String successPayment(#RequestParam(value = "id") Integer id,#RequestParam(value = "paymentId") String paymentId,#RequestParam(value = "PayerID") String PayerID) throws Exception {
System.out.println(id+" "+paymentId+" "+PayerID);
try {
Payment payment = service.executePayment(paymentId, PayerID);
if(payment.getState().equals("approved")){
Order order = orderServices.findOrderById(id);
order.setOrderState(OrderState.PAID);
orderServices.saveOrder(order);
return "success";
}
} catch (PayPalRESTException e) {
throw new Exception("Error occured while processing payment!");
}
return "Done";
}
Service
#Autowired
private APIContext apiContext;
public Payment createPayment(
Double total,
String currency,
String method,
String intent,
String description,
String cancelUrl,
String successUrl) throws PayPalRESTException {
Amount amount = new Amount();
amount.setCurrency(currency);
total = new BigDecimal(total).setScale(2, RoundingMode.HALF_UP).doubleValue();
amount.setTotal(String.format("%.2f", total));
Transaction transaction = new Transaction();
transaction.setDescription(description);
transaction.setAmount(amount);
List<Transaction> transactions = new ArrayList<>();
transactions.add(transaction);
Payer payer = new Payer();
payer.setPaymentMethod(method.toString());
Payment payment = new Payment();
payment.setIntent(intent.toString());
payment.setPayer(payer);
payment.setTransactions(transactions);
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setCancelUrl(cancelUrl);
redirectUrls.setReturnUrl(successUrl);
payment.setRedirectUrls(redirectUrls);
return payment.create(apiContext);
}
public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException{
Payment payment = new Payment();
payment.setId(paymentId);
PaymentExecution paymentExecute = new PaymentExecution();
paymentExecute.setPayerId(payerId);
return payment.execute(apiContext, paymentExecute);
}
Config
#Value("${paypal.client.id}")
private String clientId;
#Value("${paypal.mode}")
private String paypalMode;
#Value("${paypal.client.secret}")
private String clientSecret;
#Bean
public Map<String, String> paypalSdkConfig(){
Map<String, String> sdkConfig = new HashMap<>();
sdkConfig.put("mode", paypalMode);
return sdkConfig;
}
#Bean
public OAuthTokenCredential authTokenCredential(){
return new OAuthTokenCredential(clientId, clientSecret, paypalSdkConfig());
}
#Bean
public APIContext apiContext() throws PayPalRESTException{
APIContext apiContext = new APIContext(authTokenCredential().getAccessToken());
apiContext.setConfigurationMap(paypalSdkConfig());
return apiContext;
}
This is the error:
Response code: 404 Error response: {"name":"INVALID_RESOURCE_ID","message":"Requested resource ID was not found.","information_link":"https://developer.paypal.com/docs/api/payments/#errors","debug_id":"c2dc1e86af7fe"}
The checkout/paypal dont give any error, and works well i think, it got me redirect to my frontend, where i make second request, but there is when error comes..
I really dont know what is the problem..
It appears you're integrating the old v1/payments API. You should instead integrate using the current v2/checkout/orders.
See the guide at https://developer.paypal.com/docs/checkout/reference/server-integration/
The best approval flow to pair it with is https://developer.paypal.com/demo/checkout/#/pattern/server
With v2/checkout/orders, always use intent:capture unless you have very specific and well-defined business reasons to add an intervening authorization step
I'm writing j-unit Test-cases for my services and in which i couldn't mock service Response properly, Which is giving me a null. can somebody help me in this issue.
public ResponseEntity<Void> lockGet(
#ApiParam(value = "Unique identifier for this request.", required = true) #RequestHeader(value = "service-id", required = true) String serviceId,
#ApiParam(value = "Logged in userid.", required = true) #RequestHeader(value = "user-id", required = true) String userId,
#ApiParam(value = "Unique messageid.", required = true) #RequestHeader(value = "message-id", required = true) String messageId,
#RequestHeader(value = "access-token", required = true) String accessToken,
#ApiParam(value = "Unique id of the doamin of the entity", required = true) #RequestParam(value = "lockDomainId", required = true) Long lockDomainId,
#ApiParam(value = "Unique id of the entity to be fetched", required = true) #RequestParam(value = "lockEntityId", required = true) Long lockEntityId,
HttpServletRequest request, HttpServletResponse response) {
ResponseEntity<Void> result = null;
if (request.getAttribute("user-id") != null)
userId = (String) request.getAttribute("user-id");
String logContext = "||" + lockDomainId + "|" + lockEntityId + "||";
ThreadContext.put("context", logContext);
long t1 = System.currentTimeMillis();
LOG.info("Method Entry: lockGet" + logContext);
ServiceRequest serviceRequest = AppUtils.mapGetRequestHeaderToServiceRequest(serviceId, userId, lockDomainId,
lockEntityId);
try {
ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
// set all the response headers got from serviceResponse
HeaderUtils.setResponseHeaders(serviceResponse.getResponseHeaders(), response);
result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
} catch (Exception ex) {
LOG.error("Error in lockGet", ex);
result = new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
}
ThreadContext.put("responseTime", String.valueOf(System.currentTimeMillis() - t1));
LOG.info("Method Exit: lockGet");
return result;
}
#Test
public void testLockGetForError() {
request.setAttribute("user-id","TestUser");
ServiceRequest serviceRequest = new ServiceRequest();
serviceRequest.setUserId("TestUser");
ServiceResponse serviceResponse = new ServiceResponse();
LockService service = Mockito.mock(LockService.class);
when(service.getLock(serviceRequest)).thenReturn(serviceResponse);
// ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
ResponseEntity<Void> result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
ResponseEntity<Void> lockGet = lockApiController.lockGet("1234", "TestUser", "TestMessage", "TestTkn", 12345L, 12345L, request, response);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, lockGet.getStatusCode());
}
I tried in different scenario's which couldn't fix this issue. Can someone help me out. Thanks in advance.
From the code that you have put , the issue that i see is that you are actually mocking the LockService object but when calling the lockApiController.lockGet method the code is not actually working with the mocked LockService since lockApiController has an LockService object of it's own.
One way to solve this issue is to inject the mocked LockService
object into the lockApiController object using #Spy. This way
when the getLock() is called it will be actually called on the
mocked object and will return the mock response provided.
So in your test :
#Test
public void testLockGetForError() {
LockService service = Mockito.mock(LockService.class);
LockApiController lockApiController = Mockito.spy(new LockApiController(service));
request.setAttribute("user-id","TestUser");
ServiceRequest serviceRequest = new ServiceRequest();
serviceRequest.setUserId("TestUser");
ServiceResponse serviceResponse = new ServiceResponse();
when(service.getLock(serviceRequest)).thenReturn(serviceResponse);
// ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
ResponseEntity<Void> result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
ResponseEntity<Void> lockGet = lockApiController.lockGet("1234", "TestUser", "TestMessage", "TestTkn", 12345L, 12345L, request, response);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, lockGet.getStatusCode());
}
So you can try passing the mocked LockService object to the spy object.
Another way is to try using the #InjectMocks to inject the mocked
object into the LockApiController.
#InjectMocks marks a field on which injection should be performed. Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection – in this order. If any of the given injection strategy fail, then Mockito won’t report failure.
For example:
#Mock
Map<String, String> wordMap;
#InjectMocks
MyDictionary dic = new MyDictionary();
#Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");
assertEquals("aMeaning", dic.getMeaning("aWord"));
}
For the class:
public class MyDictionary {
Map<String, String> wordMap;
public MyDictionary() {
wordMap = new HashMap<String, String>();
}
public void add(final String word, final String meaning) {
wordMap.put(word, meaning);
}
public String getMeaning(final String word) {
return wordMap.get(word);
}
}
For both of these to work , you must be having a constructor or appropriate setters to set the mock object to the LockApiController class.
Reference : https://howtodoinjava.com/mockito/mockito-annotations/
I am developing a microservice application and I need to test a post request
to a controller. Testing manually works but the test case always returns null.
I've read many similar questions here in Stackoverflow and documentation but haven't figured out yet what I am missing.
Here is what I currently have and what I tried in order to make it work:
//Profile controller method need to be tested
#RequestMapping(path = "/", method = RequestMethod.POST)
public ResponseEntity<Profile> createProfile(#Valid #RequestBody User user, UriComponentsBuilder ucBuilder) {
Profile createdProfile = profileService.create(user); // line that returns null in the test
if (createdProfile == null) {
System.out.println("Profile already exist");
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/{name}").buildAndExpand(createdProfile.getName()).toUri());
return new ResponseEntity<>(createdProfile , headers, HttpStatus.CREATED);
}
//ProfileService create function that returns null in the test case
public Profile create(User user) {
Profile existing = repository.findByName(user.getUsername());
Assert.isNull(existing, "profile already exists: " + user.getUsername());
authClient.createUser(user); //Feign client request
Profile profile = new Profile();
profile.setName(user.getUsername());
repository.save(profile);
return profile;
}
// The test case
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ProfileApplication.class)
#WebAppConfiguration
public class ProfileControllerTest {
#InjectMocks
private ProfileController profileController;
#Mock
private ProfileService profileService;
private MockMvc mockMvc;
private static final ObjectMapper mapper = new ObjectMapper();
private MediaType contentType = MediaType.APPLICATION_JSON;
#Before
public void setup() {
initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(profileController).build();
}
#Test
public void shouldCreateNewProfile() throws Exception {
final User user = new User();
user.setUsername("testuser");
user.setPassword("password");
String userJson = mapper.writeValueAsString(user);
mockMvc.perform(post("/").contentType(contentType).content(userJson))
.andExpect(jsonPath("$.username").value(user.getUsername()))
.andExpect(status().isCreated());
}
}
Tried to add when/thenReturn before post but still returns 409 response with null object.
when(profileService.create(user)).thenReturn(profile);
You're using a mock profileService in your test, and you never tell that mock what to return. So it returns null.
You need something like
when(profileService.create(any(User.class)).thenReturn(new Profile(...));
Note that using
when(profileService.create(user).thenReturn(new Profile(...));
will only work if you properly override equals() (and hashCode()) in the User class, because the actual User instance that the controller receives is a serialized/deserialized copy of the user you have in your test, and not the same instance.
This is what I am trying to achieve:
I have an update request object and user is allowed to do Partial Updates. But I want to validate the field only if it is in the request body. Otherwise, it is OK to be null. To achieve this, I am using GroupSequenceProvider to let the Validator know what groups to validate. What am I doing wrong here? If there is a blunder, how do I fix it?
Documentation: https://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-groups.html#example-implementing-using-default-group-sequence-provider
#GroupSequenceProvider(UpdateUserRegistrationGroupSequenceProvider.class)
public class UpdateUserRegistrationRequestV1 {
#NotBlank(groups = {EmailExistsInRequest.class})
#Email(groups = {EmailExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {EmailExistsInRequest.class})
private String email;
#NotNull(groups = {PasswordExistsInRequest.class})
#Size(min = 8, max = 255, groups = {PasswordExistsInRequest.class})
private String password;
#NotNull(groups = {FirstNameExistsInRequest.class})
#Size(max = 255, groups = {FirstNameExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {FirstNameExistsInRequest.class})
private String firstName;
// THERE ARE GETTERS AND SETTERS BELOW
}
Group Sequence Provider Code:
public class UpdateUserRegistrationGroupSequenceProvider implements DefaultGroupSequenceProvider<UpdateUserRegistrationRequestV1> {
public interface EmailExistsInRequest {}
public interface PasswordExistsInRequest {}
public interface FirstNameExistsInRequest {}
#Override
public List<Class<?>> getValidationGroups(UpdateUserRegistrationRequestV1 updateUserRegistrationRequestV1) {
List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
defaultGroupSequence.add(Default.class);
defaultGroupSequence.add(UpdateUserRegistrationRequestV1.class);
if(StringUtils.hasText(updateUserRegistrationRequestV1.getEmail())) {
defaultGroupSequence.add(EmailExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getPassword())) {
defaultGroupSequence.add(PasswordExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getFirstName())) {
defaultGroupSequence.add(FirstNameExistsInRequest.class);
}
return defaultGroupSequence;
}
}
I am using Spring MVC, so this is how my controller method looks,
#RequestMapping(value = "/{userId}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateUser(#PathVariable("userId") Long userId,
#RequestBody #Valid UpdateUserRegistrationRequestV1 request) {
logger.info("Received update request = " + request + " for userId = " + userId);
registrationService.updateUser(userId, conversionService.convert(request, User.class));
}
Now the problem is, the parameter "updateUserRegistrationRequestV1" in the UpdateUserRegistrationGroupSequenceProvider.getValidationGroups method is null. This is the request object that I am sending in the request body and I am sending email field with it.
What am I doing wrong?
I too went through the same issue ,and hopefully solved it
You just have to check the object is null and put all your conditions inside it.
public List<Class<?>> getValidationGroups(Employee object) {
List<Class<?>> sequence = new ArrayList<>();
//first check if the object is null
if(object != null ){
if (!object.isDraft()) {
sequence.add(Second.class);
}
}
// Apply all validation rules from default group
sequence.add(Employee.class);
return sequence;
}