I have jHipster Project with 2 Entities - User and Client. Client has field "user_id" which keeps user_id of that user which created a client entity.
ClientResource.java
#RestController
#RequestMapping("/api")
public class ClientResource {
private static final String ENTITY_NAME = "client";
private final Logger log = LoggerFactory.getLogger(ClientResource.class);
private final ClientService clientService;
private final UserService userService;
private final ClientQueryService clientQueryService;
public ClientResource(ClientService clientService, ClientQueryService clientQueryService, UserService userService) {
this.clientService = clientService;
this.clientQueryService = clientQueryService;
this.userService = userService;
}
....................
#PostMapping("/clients")
#Timed
public ResponseEntity<ClientDTO> createClient(#RequestBody ClientDTO clientDTO) throws URISyntaxException {
log.debug("REST request to save Client : {}", clientDTO);
if (clientDTO.getId() != null) {
throw new BadRequestAlertException("A new client cannot already have an ID", ENTITY_NAME, "idexists");
}
String login = SecurityUtils.getCurrentUserLogin().toString();
Long loggedUserId = userService.getUserWithAuthoritiesByLogin(login).get().getId();
Here i got exception:
Exception in com.mycompany.hiptest.web.rest.ClientResource.createClient() with cause = 'NULL' and exception = 'No value present'
java.util.NoSuchElementException: No value present
I guess because i haven' a initilized clientService variable.
But how clientService got value? I didn't found any calls of ClientResource constructor.
Related
I have the following problem:
I want to test if a user registers successfully. I'm not doing this over a UI but via Postman. The problem is that I get an exception when I use the POST Command. I have already checked all annotations.
Postman Screenshot
Exception:
java.lang.IllegalArgumentException: rawPassword cannot be null
at org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(BCryptPasswordEncoder.java:103) ~[spring-security-core-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at com.example.application.backend.data.service.UserService.singUpUser(UserService.java:41) ~[classes/:na]
at com.example.application.backend.data.registration.RegistrationService.register(RegistrationService.java:22) ~[classes/:na]
at com.example.application.backend.data.registration.RegistrationController.register(RegistrationController.java:18)
This is my UserService Class:
private final static String USER_NOT_FOUND_MSG = "user with email %s not found";
#Autowired
private final UserRepository userRepository;
#Autowired
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public UserService(
UserRepository userRepository,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userRepository = userRepository;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return userRepository.findByEmail(email)
.orElseThrow(() ->
new UsernameNotFoundException(String.format(USER_NOT_FOUND_MSG, email)));
}
public String singUpUser(User user) {
boolean userExists = userRepository.findByEmail(user.getEmail()).isPresent();
if(userExists){
throw new IllegalStateException("email already taken");
}
String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user);
return "it works";
}
Registration Service Class:
#Autowired
private final UserService userService;
private final EmailValidator emailValidator;
public String register(RegistrationRequest request) {
boolean isValidEmail = emailValidator.test(request.getEmail());
if (!isValidEmail) {
throw new IllegalStateException("email not valid");
}
return userService.singUpUser(
new User(
request.getFirstName(),
request.getLastName(),
request.getEmail(),
request.getPassword(),
UserRole.USER
)
);
}
public RegistrationService(UserService userService, EmailValidator emailValidator) {
this.userService = userService;
this.emailValidator = emailValidator;
}
Registration Controller Class:
#Autowired
private RegistrationService registrationService;
#PostMapping
public String register(#RequestBody RegistrationRequest request) {
return registrationService.register(request);
}
This error occurs when the password string that is fed to the bCryptEncoder is empty or null.
In your UserService.java class,
String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword());
user.getPassword() is null, which means in RegistrationService.java class,
request.getPassword()
is fetching a null value.
Please check if you are getting the correct parameter name for password from the request object. If possible, add some logger statements in your code and debug.
GitHub PR
It is working. The problem was that the #Column annotations were set to nullable false.
Expanding #Sidharth's answer.
For anyone experiencing this problem check your password getter at AppUser.java class. It is probably returning null.
Change
public String getPassword(){return null;}
To
public String getPassword(){return password;}
please pay attention when we import the module request body
make sure the import is org.springframework.web.bind.annotation.RequestBody;
I have a class:
#Component
#NoArgsConstructor
public class ServiceFactory {
private CustomerService customerService;
private ClientService clientService;
private Map<OrderType, SettlementService> settlementServiceMap;
public ServiceFactory(CustomerService customerService, ClientService clientService) {
this.customerService = customerService;
this.clientService = clientService;
this.settlementServiceMap = new EnumMap<OrderType, SettlementService>(OrderType.class){{
put(CUSTOMER_CREDIT_ORDER, customerService);
put(CLIENT_CREDIT_ORDER, clientService);
put(CLIENT_DEBIT_ORDER, clientService);
}};
}
public SettlementService provideService(OrderType orderType){
Optional<SettlementService> settlementService = Optional.ofNullable(settlementServiceMap.get(orderType));
if (!settlementService.isPresent()){
throw new ApplicationException("Wrong order type");
}
return settlementService.get();
}
}
I'm getting NullPointerException since the services have not been initialized. A map contains orderType as a key and reference to service as a value. What is the proper way of populating the map along with services?
I learning Spring Boot web application with .jsp, and I'm struggling a lot with the testing concepts. From the SO and YT guides I implemented the Mockito thing, but honestly I do not clearly undesrtand how does it work.
I have a Registration form with 4 fields for name, lastname, email and password. This POST request is handled by the registerAction method in RegisterController. In this method I have two self-written validators for email and password. The tests should handle the cases when User data are given properly and if the errors are sent when inputs are not correct.
I tried to write tests for the controller but I'm constantly getting an exception NullPointerExpection. Looking into the debugger, the User object sent from the testing class has null attributes, which probably is the reason the exceptions.
Testing class:
#SpringBootTest
#AutoConfigureMockMvc
class RegisterControllerTest {
#Autowired
private WebApplicationContext wac;
#MockBean
private UserService userService;
#Autowired
private Gson gson;
#Autowired
private MockMvc mockMvc;
#BeforeEach
void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.apply(springSecurity()).build();
}
#Test
void show_register_action() throws Exception {
User user = prepareUserEmpty();
this.mockMvc.perform(post("/adduser")
.contentType(MediaType.APPLICATION_JSON)
.content(gson.toJson(user)))
.andDo(print())
.andExpect(status().isOk());
}
private User prepareUserEmpty(){
User user = new User();
user.setEmail("");
user.setPassword("");
user.setName("");
user.setLastName("");
return user;
}
}
RegisterController:
#Controller public class RegisterController {
#Autowired
private UserService userService;
#Autowired
private EmailSender emailSender;
#Autowired
MessageSource messageSource; // Allows to obtain messages from message.properties to Java code
#POST
#RequestMapping(value = "/adduser")
public String registerAction(User user, BindingResult result, Model model, Locale locale){ // BindingResult for validation, Locale for messageSource
String returnPage = "register";
User userExist = userService.findUserByEmail(user.getEmail());
new UserRegisterValidator().validate(user, result);
new UserRegisterValidator().validateEmailExist(userExist, result);
if (!(result.hasErrors())){
userService.saveUser(user);
model.addAttribute("message", messageSource.getMessage("user.register.success.email", null, locale));
returnPage = "index";
}
return returnPage;
} }
Validators:
public class UserRegisterValidator implements Validator {
#Override
public boolean supports(Class <?> cls){
return User.class.equals(cls);
}
#Override
public void validate(Object obj, Errors errors){
User u = (User) obj;
ValidationUtils.rejectIfEmpty(errors, "name", "error.userName.empty");
ValidationUtils.rejectIfEmpty(errors, "lastName", "error.userLastName.empty");
ValidationUtils.rejectIfEmpty(errors, "email", "error.userEmail.empty");
ValidationUtils.rejectIfEmpty(errors, "password", "error.userPassword.empty");
if (!u.getEmail().equals(null)){
boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.EMAIL_PATTERN, u.getEmail());
if (!isMatch)
errors.rejectValue("email", "error.userEmailIsNotMatch");
}
if (!u.getPassword().equals(null)){
boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.PASSWORD_PATTERN, u.getPassword());
if (!isMatch)
errors.rejectValue("password", "error.userPasswordIsNotMatch");
}
}
public void validateEmailExist(User user, Errors errors){
if (user != null)
errors.rejectValue("email", "error.userEmailExist");
}
}
I am trying to mock an object which is calling third party service but my mocked class is not being used while executing my test case. Instead it makes an actual call to the third party service. Does anybody have an idea why?
My when()then() works.
Here is my integration test class:
public class CheckoutStepsAddressITest extends AbstractITest {
//Class to be tested
#Autowired private CheckoutStepsAddressUtil checkoutStepsAddressUtil;
//Dependencies (will be mocked)
private CustomerService customerService;
//Test data
private AddressResponse addressResponse;
private CheckoutAddressView checkoutAddressView;
private AddressView addressView;
#Before
public void setup() {
addressResponse = createAddressResponse();
customerService = mock(CustomerService.class);
checkoutAddressView = new CheckoutAddressView();
checkoutAddressView.setNewAddress(createAddressView());
addressView = createAddressView();
}
public AddressResponse createAddressResponse() {
AddressDto addressDto = new AddressDto();
addressDto.setFirstName("tin");
addressDto.setLastName("tin");
addressDto.setCity("US");
addressDto.setZipCode("10212");
addressDto.setStreet1("street 1");
addressDto.setStreet2("street 2");
addressDto.setCountryCode("DE");
addressDto.setCompany("abc");
AddressResponse response = new AddressResponse();
response.setAddresses(Collections.singletonList(addressDto));
ValidationResult validationResult = new ValidationResult();
validationResult.setValidationStatus(JsonResponseStatus.OK);
response.setValidationResult(validationResult);
return response;
}
public AddressView createAddressView() {
AddressView addressView = new AddressView();
addressView.setFirstName("tin");
addressView.setLastName("tin");
addressView.setCity("US");
addressView.setZipCode("10212");
addressView.setStreet1("street 1");
addressView.setStreet2("street 2");
addressView.setCountryCode("DE");
addressView.setCompany("abc");
return addressView;
}
#Test
public void testCheckForCustomerAndUpdateAddress() throws UnexpectedException {
Mockito.when(customerService.updateAddress(addressView, UUID.randomUUID(), "BILLINGADDRESS", new JsonMessages())).thenReturn(addressResponse);
checkoutStepsAddressUtil.checkForCustomerAndUpdateAddress(UUID.randomUUID().toString(), checkoutAddressView, new JsonMessages(), UUID.randomUUID());
}
}
and here is the actual method to test
#Component
public class CheckoutStepsAddressUtil {
private static final Logger LOG = LoggerFactory.getLogger(CheckoutStepsAddressUtil.class);
#Autowired private CustomerService customerService;
#Autowired private UrlBuilder urlBuilder;
#Autowired private CustomerViewBuilder customerViewBuilder;
#Autowired private CheckoutViewBuilder checkoutViewBuilder;
#Autowired private CheckoutUtil checkoutUtil;
#Autowired private OfferService offerService;
public AddressView checkForCustomerAndUpdateAddress(String addressId, CheckoutAddressView checkoutView, JsonMessages messages, UUID customerId) throws UnexpectedException {
LOG.info("Entering");
AddressView addressView = null;
//check if the customer Id is null, if yes then return the error response else proceed to update
if (customerId == null) {
messages.addError(CheckoutStepAjaxControllerConstants.SHOP_CHECKOUT_ADDRESSES_MISSING_OFFER_OR_CUSTOMER);
LOG.info("Failed to store address because of missing customer");
} else {
//Trims the empty field values to null and proceed to update
checkoutUtil.trimEmptyAddressFieldsToNull(checkoutView);
addressView = updateAddressAndCheckAddressValidationResult(addressId, checkoutView, messages, customerId);
}
return addressView;
}
/**
* Calls Customer service to update the address and then checks the Validation Result with status`ERROR`
* and adds them to `JsonMessages`
*
* #param addressId id of the address to be updated
* #param checkoutView view that has the address to update
* #param messages
* #param customerId
* #return AddressView
* #throws UnexpectedException
*/
private AddressView updateAddressAndCheckAddressValidationResult(String addressId, CheckoutAddressView checkoutView, JsonMessages messages, UUID customerId) throws UnexpectedException {
AddressView address = checkoutView.getNewAddress();
address.setAddressId(addressId);
String identifier = OfferAddressType.NEW.toLower() + ADDRESS;
AddressResponse addressResponse = customerService.updateAddress(address, customerId, identifier, messages);
checkAddressValidationResponseFromCustomer(messages, identifier, addressResponse);
return address;
}
UPDATED: Solved my problem by doing this
#RunWith(MockitoJUnitRunner.class)
public class CheckoutStepsAddressUtilITest extends AbstractITest {
//Mock all the dependencies here
#Mock
private CustomerService customerService;
#Mock
private UrlBuilder urlBuilder;
#Mock
private CustomerViewBuilder customerViewBuilder;
#Mock
private CheckoutViewBuilder checkoutViewBuilder;
#Mock
private CheckoutUtil checkoutUtil;
#Mock
private OfferService offerService;
//Injects all the dependencies
#InjectMocks
private CheckoutStepsAddressUtil checkoutStepsAddressUtil;
//Test data
private AddressResponse addressResponse;
private CheckoutAddressView checkoutAddressView;
private AddressView actualAddressView;
#Before
public void setup() {
addressResponse = createAddressResponse();
checkoutAddressView = new CheckoutAddressView();
checkoutAddressView.setNewAddress(createAddressView());
actualAddressView = createAddressView();
}
#Test
public void testCheckForCustomerAndUpdateAddress() throws UnexpectedException {
Mockito.when(customerService.updateAddress(any(), any(), anyString(), any())).thenReturn(addressResponse);
AddressView expectedAddressView = checkoutStepsAddressUtil.checkForCustomerAndUpdateAddress(UUID.randomUUID().toString(), checkoutAddressView, new JsonMessages(), UUID.randomUUID());
assertNotNull(expectedAddressView);
assertEquals(actualAddressView.getFirstName(), expectedAddressView.getFirstName());
}
The customer service that is called is not the one you mock.
The Autowire annotation of your service in your test wires all the services with the same annotation in you CheckoutStepsAddressUtil. Which means that when you run your tests, Spring has no way of knowing that it should replace the customerService instance by your mock. Hence the call to the actual service.
You need a way to inject your mocked service into the service you want to test.
One way to do it is through ReflectionTestUtils, adding this line to your test before the actual call to your tested method should do the trick:
ReflectionTestUtils.setField(checkoutStepsAddressUtil, "customerService", customerService);
Note that in this case you are still autowiring the other dependencies of your service so may still have a problem with other calls.
Some of the objects that use in the when.then are not the same ones that are actually passed to this method during execution. I would play around with wildcards here:
#Test
public void testCheckForCustomerAndUpdateAddress() throws UnexpectedException {
UUID uuid = UUID.randomUUID();
Mockito.when(customerService.updateAddress(
eq(addressView), eq(uuid), eq("BILLINGADDRESS"), any(JsonMessages.class))
.thenReturn(addressResponse);
checkoutStepsAddressUtil.checkForCustomerAndUpdateAddress(uuid.toString(),checkoutAddressView, new JsonMessages(), uuid );
}
Used: Mockito.any(), Mockito.eq();
I have a test class that looks like this
I found out that the test when i use #WebMvcTest Does not recognize the url for some reason.Any help would suffice please .
After debugging i get that DefaultRequestBuilder =Null, DefaultRequestMatcher size=0
#AutoConfigureMockMvc()
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest({ShoppingCartController.class, HomeController.class})
#ContextConfiguration(classes = {SecurityConfig.class})
public class ShoppingCartControllerTest {
#Autowired
WebApplicationContext context;
#Autowired
private MockMvc mockMvc;
#MockBean
private BookService bookService;
#MockBean
private UserService userService;
#MockBean
private CartItemService cartItemService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void showLoginPage() throws Exception {
mockMvc.perform(get("/login")
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML)
)
.andExpect(model().attributeExists("classActiveLogin"))
.andReturn();
}
#Test
#WithMockUser(username = "V", authorities = {"USER"})
public void addItemToShoppingCart() throws Exception {
CartItem cartItem = new CartItem();
String qty = "2";
Book book = new Book();
User user = new User();
book.setId(1L);
book.getId();
cartItem.setBook(book);
when(userService.findByUsername(anyString())).thenReturn(user);
when(bookService.findOne(anyLong())).thenReturn(book);
when(cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty))).thenReturn(cartItem);
ObjectMapper mapper = new ObjectMapper();
String bookAsString = mapper.writeValueAsString(book);
mockMvc
.perform(get("/shoppingCart/addItem")
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML)
.param("book", bookAsString)
.param("qty", qty))
.andReturn();
}
#Configuration
#Import({PropertyTestConfiguration.class, SecurityUtility.class})
static class ContextConfiguration {
}
}
Only the test addItemToShoppingcCart passes , the other three have the same error as shown below , It is definitely not importing everything I need but I cant figure out what exactly it is.
java.lang.AssertionError: No ModelAndView found
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:35)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:65)
I don't understand why I t cant find models and views but when I use #
SpringBootTest and EasyMock everything passes ? what can I do ?
These are my controllers
#RequestMapping("/login")
public String login(Model model) {
model.addAttribute("classActiveLogin", true);
return "Myaccount";
}
#PreAuthorize("hasAuthority('USER')")
#RequestMapping("/addItem")
public String addItem(
#ModelAttribute("book") Book book,
#ModelAttribute("qty") String qty,
Model model, Principal principal
) {
User user = userService.findByUsername(principal.getName());
try {
book = bookService.findOne(book.getId());
if (Integer.parseInt(qty) > book.getInStockNumber()) {
model.addAttribute("notEnoughStock", true);
return "forward:/bookDetail?id=" + book.getId();
}
CartItem cartItem = cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty));
model.addAttribute("addBookSuccess", true);
} catch (NullPointerException e) {
}
return "forward:/bookDetail?id=" + book.getId();
}
I have two controllers i am testing
#Controller
public class HomeController {
#Autowired
private JavaMailSender mailSender;
#Autowired
private MailConstructor mailConstructor;
#Autowired
private UserService userService;
#RequestMapping("/login")
public String login(Model model) {
model.addAttribute("classActiveLogin", true);
return "Myaccount";
}
And Second one which has Class level Mapping
#Controller
#RequestMapping("/shoppingCart")
public class ShoppingCartController {
#Autowired
private UserService userService;
// autowired services here
#PreAuthorize("hasAuthority('USER')")
#RequestMapping("/addItem")
public String addItem(
#ModelAttribute("book") Book book,
#ModelAttribute("qty") String qty,
Model model, Principal principal
) {
User user = userService.findByUsername(principal.getName());
try {
book = bookService.findOne(book.getId());
if (Integer.parseInt(qty) > book.getInStockNumber()) {
model.addAttribute("notEnoughStock", true);
return "forward:/bookDetail?id=" + book.getId();
}
CartItem cartItem = cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty));
model.addAttribute("addBookSuccess", true);
} catch (NullPointerException e) {
}
return "forward:/bookDetail?id=" + book.getId();
}