Skip to content

Commit

Permalink
add unit test for purchase lottery method
Browse files Browse the repository at this point in the history
add validation level at Controller

add ConstrainViolationException in ControllerHandleException
  • Loading branch information
ce-pong committed Feb 26, 2024
1 parent 99a1b3a commit ba34a6e
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kbtg.bootcamp.posttest.exception;

import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
Expand Down Expand Up @@ -46,4 +47,47 @@ public ApiErrorResponse handleValidationExceptions(MethodArgumentNotValidExcepti
request.getDescription(false)
);
}

@ExceptionHandler(value = {NotFoundException.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiErrorResponse handleNotFoundException(NotFoundException exception,WebRequest request){
return new ApiErrorResponse(
LocalDateTime.now(),
HttpStatus.NOT_FOUND.value(),
HttpStatus.NOT_FOUND.getReasonPhrase(),
exception.getMessage(),
request.getDescription(false)
);
}

@ExceptionHandler(value = {LotteryRunOutException.class})
@ResponseStatus(HttpStatus.CONFLICT)
public ApiErrorResponse handleLotteryRunOutException(LotteryRunOutException exception,WebRequest request){
return new ApiErrorResponse(
LocalDateTime.now(),
HttpStatus.CONFLICT.value(),
HttpStatus.CONFLICT.getReasonPhrase(),
exception.getMessage(),
request.getDescription(false)
);
}

@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse handleConstraintViolationException(ConstraintViolationException exception, WebRequest request) {
List<String> error = exception.getConstraintViolations()
.stream()
.map(f -> f.getMessage())
.toList();

return new ApiErrorResponse(
LocalDateTime.now(),
HttpStatus.BAD_REQUEST.value(),
HttpStatus.BAD_REQUEST.getReasonPhrase(),
String.join(",",error),
request.getDescription(false)
);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.kbtg.bootcamp.posttest.exception;

public class LotteryRunOutException extends RuntimeException{
public LotteryRunOutException(String message){
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.web.bind.annotation.*;

@RestController
@Validated
public class LotteryController {

private LotteryService lotteryService;
Expand Down Expand Up @@ -37,6 +38,6 @@ public LotteryPurchaseReponse purchaseTicket(
@PathVariable(value = "userId") @TenDigitUser String userId,
@PathVariable(value = "ticketId") @SixDigitTicket String ticketId){

return null;
return lotteryService.purchaseLottery(userId,ticketId);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kbtg.bootcamp.posttest.lottery;

public record LotteryPurchaseReponse(int id) {
public record LotteryPurchaseReponse(String id) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import com.kbtg.bootcamp.posttest.exception.InternalServerException;

import com.kbtg.bootcamp.posttest.exception.LotteryRunOutException;
import com.kbtg.bootcamp.posttest.exception.NotFoundException;
import com.kbtg.bootcamp.posttest.user.User;
import com.kbtg.bootcamp.posttest.user.UserRepository;
import com.kbtg.bootcamp.posttest.user.UserTicket;
import com.kbtg.bootcamp.posttest.user.UserTicketRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -27,9 +30,6 @@ public LotteryService(LotteryRepository lotteryRepository, UserTicketRepository
this.userRepository = userRepository;
}

public Boolean checkValidTicket(String ticket){
return true;
}
public LotteryListResponse getAvailableTicketIds() {
try{
List<Lottery> tickets = lotteryRepository.findByAmountMoreThanZero();
Expand Down Expand Up @@ -63,6 +63,42 @@ public LotteryResponse createLottery(LotteryDto request){
@Transactional
public LotteryPurchaseReponse purchaseLottery(String userId,String ticketId){

return null;
Optional<Lottery> optionalLottery = lotteryRepository.findById(ticketId);
Lottery lottery;
if(optionalLottery.isEmpty()){
throw new NotFoundException("Ticket "+ticketId+" not found");
}

lottery = optionalLottery.get();

if(lottery.getAmount() == 0){
throw new LotteryRunOutException("Ticket "+ticketId+" has already been purchased");
}

UserTicket userTicket;
try{
User user;
Optional<User> optionalUser = userRepository.findById(userId);
if(optionalUser.isEmpty()){
user = new User(userId);
userRepository.save(user);
}else{
user = optionalUser.get();
}

// create purchase record
userTicket = new UserTicket(lottery,user);
userTicket = userTicketRepository.save(userTicket);

// discount from storage
lottery.setAmount(lottery.getAmount()-1);
lotteryRepository.save(lottery);

}catch (Exception ex){
throw new InternalServerException("Failed to purchase lottery");
}

String recordId = Integer.toString(userTicket.getId());
return new LotteryPurchaseReponse(recordId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public class UserTicket {
@JoinColumn(name = "user_id")
private User user;

public UserTicket() {
}

public UserTicket(Lottery lottery, User user) {
this.lottery = lottery;
this.user = user;
}

public int getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,4 @@ public void createTicket_withInvalidData_ShouldReturn400() throws Exception {
}



}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.kbtg.bootcamp.posttest.lottery;

import com.kbtg.bootcamp.posttest.exception.InternalServerException;
import com.kbtg.bootcamp.posttest.exception.LotteryRunOutException;
import com.kbtg.bootcamp.posttest.exception.NotFoundException;
import com.kbtg.bootcamp.posttest.user.User;
import com.kbtg.bootcamp.posttest.user.UserRepository;
import com.kbtg.bootcamp.posttest.user.UserTicket;
Expand All @@ -17,6 +19,7 @@

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -53,7 +56,7 @@ void whenGetAvailableTicket_withNoData_ShouldReturnResponseWithEmptyList() {

@Test
@DisplayName("Get Available Ticket IDs With Data Should Return Correctly List Of Ticket Id")
void gwhenGetAvailableTicket_withData_ShouldReturnResponseWithListStringTicketId() {
void whenGetAvailableTicket_withData_ShouldReturnResponseWithListStringTicketId() {
// Arrange
Lottery lottery1 = new Lottery();
lottery1.setTicketId("000001");
Expand Down Expand Up @@ -115,26 +118,72 @@ void whenCreateLotteryFails_ShouldThrowInternalServerException() {
}

@Test
@DisplayName("Purchase lottery should be return id from User_ticket")
void whenPurchaseLottery_ShouldReturnLotteryPurchaseResponseWithUserTicketId(){
@DisplayName("Purchase lottery throws NotFoundException if ticket is not found")
void whenPurchaseLottery_withNoTicket_ShouldReturnNotFound(){

// Arrange
String ticket = "000001";
String userId = "0123456789";
User user = new User(userId);
Lottery lottery = new Lottery(ticket,80,1);

when(lotteryRepository.findById(ticket)).thenReturn(Optional.empty());


// Act & Assert
Exception exception = assertThrows(NotFoundException.class, () -> {
lotteryService.purchaseLottery(userId,ticket);
});

String actualMessage = exception.getMessage();
String expectedMessage = "Ticket "+ticket+" not found";

assertEquals(expectedMessage,actualMessage);
}

@Test
@DisplayName("Purchase lottery throws LotteryRunOutException if ticket is already purchased")
void whenPurchaseLottery_withTicketRunOut_ShouldReturnRunOutException(){

// Arrange
String ticket = "000001";
String userId = "0123456789";
Lottery lottery = new Lottery(ticket,80,0);

when(lotteryRepository.findById(ticket)).thenReturn(Optional.of(lottery));


// Act & Assert
Exception exception = assertThrows(LotteryRunOutException.class, () -> {
lotteryService.purchaseLottery(userId,ticket);
});

String actualMessage = exception.getMessage();
String expectedMessage = "Ticket "+ticket+" has already been purchased";

assertEquals(expectedMessage,actualMessage);
}

@Test
@DisplayName("Purchase lottery return LotteryPurchaseResponse with UserTicketId")
void whenPurchaseLottery_ShouldReturnResponseWithUserTicketId(){

// Arrange
String ticket = "000001";
String userId = "0123456789";
Lottery lottery = new Lottery(ticket,80,1);
UserTicket userTicket = new UserTicket();
User user = new User(userId);
UserTicket userTicket = new UserTicket(lottery,user);
userTicket.setId(1);
userTicket.setUser(user);
userTicket.setLottery(lottery);

when(lotteryRepository.findById(ticket)).thenReturn(Optional.of(lottery));
when(userRepository.findById(userId)).thenReturn(Optional.of(user));
when(userTicketRepository.save(any(UserTicket.class))).thenReturn(userTicket);

// Act
LotteryPurchaseReponse actual = lotteryService.purchaseLottery(userId,ticket);

// Assert
int expected = 1;
String expected = "1";
assertEquals(expected,actual.id());
}
}

0 comments on commit ba34a6e

Please sign in to comment.