테스트 코드를 작성하면서 예외가 발생했을 경우에 대한 케이스 쪽에서 한 가지 궁금한 점이 생겨 찾아보고 정리하게 되었다.
BDDMockito의 willThrow를 사용하던 도중, 파라미터로 다음과 같이 작성할 수 있음을 알 수 있었다.
given(testService.func(any())).willThrow(SomeException.class);
이처럼 willThrow의 파라미터로 class를 넣을 수도 있고,
given(testService.func(any())).willThrow(new SomeException("message"));
이렇게 예외 관련 객체를 생성하여 파라미터로 넣을 수도 있다.
willThrow()
함수 안으로 들어가보니...
...와 같이 이렇게 함수가 오버로딩 되어있음을 확인할 수 있었다.
그렇다면 둘의 차이점은 무엇일까? 직접 돌려봤을 때 stack trace 정보를 나타낼 수 있는지의 여부에서 차이가 발생함을 알 수 있었다.
If you require stack trace information, use thenThrow(Throwable...) instead.
stack trace 정보를 알고 싶다면, thenThrow(Throwable...)을 사용하세요.
해당 메소드로는 발생한 예외에 대한 stack trace를 알 수 없다.
you can specify throwables to be thrown for consecutive calls. in that case the last throwable determines the behavior of further consecutive calls.
연속 호출에 대해 throw될 throwable을 지정할 수 있습니다. 이 경우 마지막 throwable은 추가 연속 호출의 동작을 결정합니다.
무슨 말일까... 잠시 고민했었는데 본인은 이렇게 이해했다.
이런 사용자 지정 예외가 있다고 가정해볼 것이다.
class CustomException extends RuntimeException {
public RuntimeException(String message) {
super(message);
}
}
그리고 실제로 로직을 수행하다가 최종적으로 던져지는 Exception은 CustomException이다.
마지막 throwable은 CustomException 최상위 class는 Throwable이다.
public class Throwable implements Serializable {
...
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}
...
}
생성자에서 fillInStackTrace()
가 호출될 것이고...
public class Throwable implements Serializable {
...
public synchronized Throwable fillInStackTrace() {
if (stackTrace != null ||
backtrace != null /* Out of protocol state */ ) {
fillInStackTrace(0);
stackTrace = UNASSIGNED_STACK;
}
return this;
}
...
}
fileInStackTrace()
는 fillnStackTrace()
를 호출할 것이다.
public class Throwable implements Serializable {
...
private native Throwable fillInStackTrace(int dummy);
...
}
이렇게 예외를 던진 이후에 순차적으로 함수를 호출한다.
본인의 생각이 틀릴 수도 있다. 하지만 결론적으로 테스트 도중 stack trace를 보고싶다면 이 willThrow
를 사용하면 된다는 사실을 알 수 있었다.
Reference
BDD의 willThrow 2가지 비교하기
본인의 궁금증을 해결해준 블로그다. 여기서는 thenThrow에 대해서 정리한 듯 하지만 같은 경우, 같은 내용이다.