Assertions
Junit5에 적혀있는 설명들을 모두 해석해봤다. 무슨 역할을 하고 있고, 어떻게 만들어졌는 지 먼저 살펴보자. ( 본인 해석과 파파고의 도움을 받았다. 따라서 올바르지 못할 수 있음. 또한 개인 견해도 포함된다. )
- Assertions is a collection of utility methods that support asserting conditions in tests.
Unless otherwise noted, a failed assertion will throw an AssertionFailedError or a subclass thereof.
- Assertion은 테스트에서 asserting 조건을 지원하는 유틸리티 메서드 집합이다. → 검증하는 데 사용되는 메서드 집합
- 실패한 메서드들은 AssertionFailedError 또는 하위 클래스를 발생시킨다.
Object Equality → 객체 동일성
- Assertion methods comparing two objects for equality, such as the assertEquals(expected, actual) and assertNotEquals(unexpected, actual) variants, are only intended to test equality for an (un-)expected value and an actual value. They are not designed for testing whether a class correctly implements Object.equals(Object). For example, assertEquals() might immediately return true when provided the same object for the expected and actual values, without calling equals(Object) at all. Tests that aim to verify the equals(Object) implementation should instead be written to explicitly verify the Object.equals(Object) contract by using assertTrue() or assertFalse() — for example, assertTrue(expected.equals(actual)), assertTrue(actual.equals(expected)), assertFalse(expected.equals(null)), etc.
- assertEquals과 assertNotEquals는 기댓값과 실제값의 동일성을 테스트하기 위한 메서드이다. Equals 메서드를 제대로 구현하였는 지 확인하기 위해서 구현된 것은 아니다. → Object 객체의 Equals 메서드의 올바른 구현과는 무관하다.
- 바로 다음 내용으로 실제 Equals를 호출하지 않고도 동일한 객체를 반환한다면 즉시 true를 반환할 수 있다고 명시되어있다.
- 따라서 실제로 Equals 구현에 대한 사항을 확인하기 위해서는
assertTrue()
또는 assertFalse()
를 사용하여 Equals 구현을 명시적으로 확인해야 된다고 되어 있다. → WOW 공식문서 안 봤으면 평생 몰랐을 뻔..
Kotlin Support - 코틀린 지원 Ok
- Additional Kotlin assertions can be found as top-level functions in the org.junit.jupiter.api package.
- 당연하게도 코틀린에 대하여 완벽한 지원을 한다. org.junit.jupiter.api 패키지 안에서 그 내용을 찾을 수 있다.
Preemptive Timeouts - Assertions 안 메서드 assertTimeoutPreemptively()
- The various assertTimeoutPreemptively() methods in this class execute the provided executable or supplier in a different thread than that of the calling code. This behavior can lead to undesirable side effects if the code that is executed within the executable or supplier relies on ThreadLocal storage.
- 존재하는 다양한
assertTimeoutPreemptively()
메서드가 인자로 제공되는 executable 또는 supplier를 호출한 코드의 스레드와는 다른 스레드에서 실행되고 이러한 동작이 호출한 코드에서 사용하는 ThreadLocal 저장소에 부작용을 가져올 수 있다는 내용이다. → 굉장히 어려운 내용.. 그러나 쉽게 가보자
- ThreadLocal이라는 것은 Java에서 동시성 이슈를 해결하기 위해 각 Thread에 고유한 자원을 보유하도록 도와주는 메커니즘이다. 그러나 해당 메서드를 사용하는 경우 별도의 Thread에서 실행되기 때문에 ThreadLocal 저장소에 의존한다면 문제가 발생할 수 있다. → ThreadLocal을 사용하거나 동시성 이슈로 인해 멀티 스레딩과 관련된 혹은 의존된 코드가 있을 경우 예상과 다르게 동작할 수 있다.
- One common example of this is the transactional testing support in the Spring Framework. Specifically, Spring's testing support binds transaction state to the current thread (via a ThreadLocal) before a test method is invoked. Consequently, if an executable or supplier provided to assertTimeoutPreemptively() invokes Spring-managed components that participate in transactions, any actions taken by those components will not be rolled back with the test-managed transaction. On the contrary, such actions will be committed to the persistent store (e.g., relational database) even though the test-managed transaction is rolled back.
- Similar side effects may be encountered with other frameworks that rely on ThreadLocal storage.
- 위의 문제로 대표적인 예시는 Spring 프레임워크에서 트랜잭션 테스트가 있다. Spring에서의 테스트는 트랜잭션 상태를 스레드에 바인딩한다. 결과적으로 해당 테스트에서
assertTimeoutPreemptively()
메서드를 사용하게 된다면 구성요소에서 작업한 사항들이 트랜잭션으로 롤백하지 않는다고 한다. 테스트 트랜잭션이 롤백되더라도 데이터베이스 저장소에 커밋되는 아주 심각한 부작용이 발생한다고 한다.
Extensibility - 확장성
- Although it is technically possible to extend this class, extension is strongly discouraged. The JUnit Team highly recommends that the methods defined in this class be used via static imports.
- Assertions 클래스를 확장하는 것은 기술적으로는 가능하지만 강력하게 권장하지 않는다고 한다. → 하지말라면 하지말자~
마무리
이번 글에서 Assertions에 포함되는 다양한 Assert 메서드를 알아보려고 했으나 Junit5 공식문서를 옮기다보니 재미있어서 설명이 길어졌다. 다음 글에서는 반드시 Assert 메서드들을 정리하고 알아보도록 하자.
참고사항
Assertions (JUnit 5.9.1 API)
글이 많은 도움이 되었습니다, 감사합니다.