이 글의 시작은 알만한 사람은 아는 극한의 츤데레 '포프 TV'형님의 영상에서 시작한다. ㅎㅎ
영상의 제목은 "Assert 어디에 넣을지 모르면 넌 주니어"이고, 오늘도 어김없이 나는 주니어이다... 😂
아무튼, 포프TV님의 가르침에 따라서 Assert에 대해서 알아보는 시간을 가져보겠다. 🔥
참고로, 포프TV는 내가 개발자를 처음 시작할 때부터 보던 채널인데, 보고 있으면 정신이 번뜩차려지게 된다.
헬스하는 분들에게 '암모니아'같은 거라고 볼수도 있을 것 같다.
이 채널을 모르는 분들은 한번쯤 영상을 봐보면 좋을 것 같다. ㅎㅎ
assert (조건) : "에러 메세지";
assert 1==2 : "1은 2가 아니지~";
Java뿐만 아니라 다양한 프로그래밍 언어에서는 assert
라는 문법을 제공한다. Exception과 마찬가지로, 코드의 타당성을 검증할 때, 사용한다. 위와 같은 형태로 사용하고, 조건을 만족하지 못하는 경우 에러를 던지고 로직을 종료시키는 역할을 한다.
그렇다면, Exception과 Assert는 어떻게 다를까?
assert
는 Exception
과 달리 코드에 작성을 해도, .jar
파일을 실행하면 동작하지 않는다. 즉, assert
는 개발 및 디버깅을 할 때 사용할 것을 전제하에 만들어진 것이라고 이해할 수 있다.
📌 실행옵션에
-ea
라는 매개변수를 넘기면assert
문도 실행되게 할 수 있다.
public void buySomething(Long productId, String message) {
assert message != null : "메세지는 Null 안됨!!!";
// ... 비지니스 로직 ...
}
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@Slf4j
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class AssertTest {
@Test
@DisplayName("assertTest")
public void assertTest() throws Exception {
try {
assert 1 == 2 : "bye";
} catch (AssertionError e) {
log.info("Catch : {}", e.getMessage());
}
log.info("Done");
}
}
assert
는 조건문이 false
일 경우, AssertionError
를 발생시킨다.
그래서 위와 같이 try-catch
로 해당 예외를 잡아보면, 잘 잡히는 것을 확인할 수 있다.
Spring에서는 assert를 좀 더 쉽고 효율적으로 사용하기 위한 클래스를 이미 제공하고 있다. 그것이 바로 Assert
인데, 바로 사용법에 대해서 알아보자.
Assert.isTrue(1 == 2, "아니지 아니지");
Assert클래스는 매우 많은 메서드를 제공하는데, 모두 위와 같은 형태로 사용하면 된다. 첫번재 인자는 조건문을 넣고, 두번째 인자에는 검증 실패시 출력할 에러 메세지를 넣으면 된다.
assert
문의 경우 조건문이 false
가 되면 AssertionError
를 뱉었다면, Assert
클래스를 사용하면 IllegalArgumentException
또는 IllegalStateException
을 던진다. 즉, 실제 운영환경에서 사용하기 좋은 형태의 Exception을 던지는 것이다.
그래서 assert
보다는 Assert
를 사용해서 코드의 명확함과 가독성등등을 높이는 것을 권장한다.
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.util.Assert;
import java.util.*;
@Slf4j
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class AssertTest {
@Test
@DisplayName("AssertionTest")
public void AssertionTest() throws Exception {
// Logical assertions
try {
Assert.isTrue(1 == 2, "isTrue");
} catch (IllegalArgumentException e) {}
try {
Assert.state(1 == 2, "state");
} catch (IllegalStateException e) {}
// Object and type assertions
String hello = "world";
Assert.notNull(hello, "notNull");
Assert.isNull(null, "isNull");
String text = "text";
Assert.isInstanceOf(String.class, text);
Assert.isAssignable(AbstractMap.class, HashMap.class);
// Text assertions
String noBlank = " ";
Assert.hasLength(noBlank, "hasLength");
String hasText = "abc";
Assert.hasText(hasText, "hasText");
String abc = "abc";
Assert.doesNotContain("a", abc, "doesNotContain");
// Collection and map assertions
Collection<Integer> list = List.of(1);
Assert.notEmpty(list, "notEmpty");
HashMap<String, String> hashMap = new HashMap();
hashMap.put("hello", "world");
Assert.notEmpty(hashMap, "notEmpty");
// Array assertions
Integer[] numbers = new Integer[1];
numbers[0] = 1;
Assert.notEmpty(numbers, "notEmpty");
Assert.noNullElements(numbers, "noNullElements");
}
}
다양한 메서드를 실행하는 테스트코드를 작성해보았다.
어지간한 경우는 모두 커버할 수 있을 만큼 메서드들이 다양하고, IllegalArgumentException 또는 IllegalStateException를 선택적으로 던질 수 있어서, 실무에서도 사용하기 매우 좋을 것 같다. 🤓