inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

주문 기능 테스트

Junit5 의 Assertions.fail 에 대해 질문이 있습니다.

1604

danaldanalcom3

작성한 질문수 2

0

@Test
public void 상품주문_재고수량초과() throws Exception {

//Given
Member member = createMember();
Item item = createBook("시골 JPA", 10000, 10); //이름, 가격, 재고

int orderCount = 11; //재고보다 많은 수량

//When
assertThrows(NotEnoughStockException.class, () -> {
orderService.order(member.getId(), item.getId(), orderCount);});

//Then
fail("재고 수량 부족 예외가 발생해야 한다.");
}

안녕하십니까. 김영한님의 강의를 열심히 수강중인 학생입니다.

Junit5에 대해 질문이 있어 글을 올립니다.

제가 Junit5를 배워보려고 강의 진행중 Junit4 대신 Junit5 를 써보았습니다.

그런데 Assertions.fail 때문에 위 코드가 자꾸 실패가 뜨더라고요.

제가 생각한 로직은 김영한님 강의에서 처럼 Assertions.assertThrows 안의 로직에서 예외를 던지면 fail까지 내려오지 않고 그대로 테스트가 성공으로 종료되며, 만약 예외를 던지지 않으면 fail까지 내려와 테스트 실패가 나오는 것이었습니다.

어떻게 코드를 수정하면 될까요?

------------------------------------------------------------------------------------------------------------------

설명이 부족한 것 같아 추가로 남깁니다.

위 코드는 재고보다 많은 수량이 입력됐을때 예외를 제대로 내뱉는지 확인하기 위한 테스트입니다.

만약 예외를 제대로 뱉었다면 김영한님 강의에서처럼 fail() 까지 안넘어가고 assertThrows 에서 테스트가 종료되고 성공으로 반환되어야 했습니다.

그런데 위 코드에서는 코드 진행이 fail까지 내려가고 그대로 실패가 뜨더라고요. 

Service, repository와 같은 기타 다른 연관 코드들은 김영한님 코드와 동일하게 작성하였으며, fail을 주석처리하고 위 테스트를 돌렸을 경우 성공처리가 됩니다.

상기 목적을 달성하려면 위 코드를 어떻게 수정하면 될까요?

junit5 실패테스트 java spring-boot spring 웹앱 JPA

답변 4

2

김소젬

저도 같은 부분이 궁금해서 댓글답니다!

 

제가 이해한게 맞다면 JUnit5의 경우 NotEnoughStockException이 예측한 오류여서 테스트가 통과된 후에 fail("재고수량 부족~")으로 넘어가기 때문에  테스트가 fail된다는 말씀이 맞나요?

 

맞다면 도움되었습니다. 감사합니다:)

0

나무늘보

안녕하세요 김소젬님

네 fail() 은 테스트를 강제로 실패하게 합니다 :)

2

나무늘보

안녕하세요 danaldanalcom3 님!

.

Assertions.assertThrows() 에서 사용자가 예측한 오류가 던져질 경우엔 테스트 성공으로 처리되며 프로세스가 중단되지 않고 다음 프로세스를 진행하게 됩니다. 테스트가 실패하면 그 테스트는 종료되지만 테스트가 통과한 경우에는 테스트의 끝 (@Test가 붙은 함수의 끝) 까지 프로세스를 계속 진행하게 됩니다.

아래는 Assertions.assertThrows() 메서드를 추적하여 살펴본 실제 구현 코드 입니다. 사용자가 오류가 날 수 있다고 전제한 코드를 실제로 실행 한뒤, 클라이언트가 예측한 오류가 나는지를 확인하는 코드 입니다. 예측한 오류가 나지 않으면 검증 실패 오류를 발생시키고, 오류는 발생했지만 클라이언트가 예측한 오류가 아닌경우에 불일치 오류를 던지고 있습니다. 이러한 오류가 던져지면 테스트는 실패로 간주됩니다. 그러나 클라이언트가 예측한 오류가 맞다면 그 오류를 그대로 반환하여 다른 처리를 하게 되고 테스트는통과로 처리 됩니다.

private static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable,
			Object messageOrSupplier) {

		try {
			executable.execute();
		}
		catch (Throwable actualException) {
			if (expectedType.isInstance(actualException)) {
				return (T) actualException;
			}
			else {
				UnrecoverableExceptions.rethrowIfUnrecoverable(actualException);
				String message = buildPrefix(nullSafeGet(messageOrSupplier))
						+ format(expectedType, actualException.getClass(), "Unexpected exception type thrown");
				throw new AssertionFailedError(message, actualException);
			}
		}

		String message = buildPrefix(nullSafeGet(messageOrSupplier))
				+ String.format("Expected %s to be thrown, but nothing was thrown.", getCanonicalName(expectedType));
		throw new AssertionFailedError(message);
	}

0

danaldanalcom3

감사합니다. 제가 무엇을 모르고 있는지 정확히 알겠네요!

2

OMG

danaldanalcom3님 제가 질문 내용을 잘못 이해했군요..

확인 해 본 결과, 최신 메뉴얼의 코드를 그대로 작성하셨다는 가정하에 

@RunWith 어노테이션 삭제,

@Test 어노테이션을 

import org.junit.jupiter.api.Test;

로 바꾸면 통과 되더라구요.

public이 생략된 것으로 Junit5가 적용된 것을 확인 하실 수 있으십니다.

0

OMG

안녕하세요. danaldanalcom3님, 공식 서포터즈 OMG입니다.

테스트 메서드 명을 보시다시피 "상품주문_재고수량초과()" 라고 작성하셨잖아요? 저라면

재고수량초과 -> assertThrows(NotEnoughStockException.class, () -> { orderService.order(member.getId(), item.getId(), orderCount);}); // 이 코드로 검증을 끝내고

--

그리고 재고수량이 초과하지 않았을 경우에 대한 테스트를 따로 만들어서 "재고수량이 몇개인데 몇개를 주문하니까 몇개가 남았다" 라는 검증을 할 것 같습니다. 하나의 테스트에는 하나의 핵심 로직 테스트를 작성하시되 케이스가 나뉘는 경우엔 각각에 대한 테스트를 작성하는게 좋은 것 같아요.

감사합니다.

0

danaldanalcom3

아니요... 질문설명이 부족한지 답변자님께서 질문에 대해 잘못이해하신거 같습니다.

저 테스트는 상품주문시 재고수량이 초과 됐을때 에러를 제대로 던지는지 확인하는 것이 목적이었어요. 그래서 orderService.order(member.getId(), item.getId(), orderCount); 를 했을 때 예외를 던지고 그대로 끝나야 했습니다. 만약 예외를 던지지 않았을 경우 테스트가 실패로 끝나게 하기 위해서 fail 메서드를 사용한거에요.  그런데 위 코드는 재고수량이 초과되어서 예외를 던지고 테스트가 성공으로 끝나야하는데 fail까지 진행되버려서 테스트가 실패로 끝납니다. 즉, 원하는대로 코드가 작동하지 않는거죠. 그래서 질문을 올린겁니다.

sdk 설정 오류

0

51

2

오탈자 - @Transactional

0

56

1

src/test/resources 테스트 경로 문제

0

50

1

상품 등록후 H2 db 출력 순서 바꿀 수 있나요?

0

64

1

MemberRepositoryTest 실행오류

0

81

1

boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)

1

183

2

강의 마지막 QueryDSL 사용 부분 질문있습니다

1

139

2

클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.

0

51

1

도메인 모델 패턴 vs 트랜잭션 스크립트 패턴

0

71

1

기본 생성자

0

60

1

h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.

0

101

1

멤버서비스테스트 부분에서 막힙니다.

0

164

4

실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?

0

116

1

초반에 h2 다운로드 과정 꼭 필요한가요?

0

119

2

자신 필드에도 get으로 접근하는 이유가 있을까요?

0

114

1

24분 27초 연관관계 편의 메서드 위치

0

113

1

단건 주문만 가능하게 한건 의도한 부분이신가요?

0

109

2

빌드 툴, Gradle

0

59

1

h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다

0

77

2

Repository에서 EntityManager 주입 방식 차이

0

90

1

롬복과 사용자 정의 setter 메서드

0

71

1

주문 목록 조회 fetch join 질문드립니다

0

81

1

dirty checking 질문드립니다.

0

83

1

동시성 관련 질문입니다

0

74

1