[7.8] JDBC - 자원객체 이해 / JUnit 사용
* 직접 자원객체를 만들고, try-with-resources 블록에 적용해서
과연 자원객체가 어떤 순서로 닫히는지 알아보자
- 먼저, 자원class 생성
이 때, AutoCloseable 인터페이스에는매개변수와 리턴타입이 없는 추상메소드가 하나 들어있음
--> functional interface 이다.
그 추상메소드를 오버라이딩 하자!
--> 이유 : try-with-resources가 닫아줄 모든 자원객체(클래스)의 요건 --> AutoCloseable 해야하기 때문
@Log4j2
@NoArgsConstructor
class Resource1 implements AutoCloseable {
@Override
public void close() throws Exception {
log.trace("close() invoked.");
} // close
} // end class
- 자원class 2개 더 생성해서 총 3개 생성
@Log4j2
@NoArgsConstructor
class Resource1 implements AutoCloseable {
@Override
public void close() throws Exception {
log.trace("close() invoked.");
} // close
} // end class
@Log4j2
@NoArgsConstructor
class Resource2 implements AutoCloseable {
@Override
public void close() throws Exception {
log.trace("close() invoked.");
} // close
} // end class
@Log4j2
@NoArgsConstructor
class Resource2 implements AutoCloseable {
@Override
public void close() throws Exception {
log.trace("close() invoked.");
} // close
} // end class
- 실행블럭 작성
public class JDBCExample7 {
public static void main(String args[]) {
Resource1 res1 = new Resource1();
Resource2 res2 = new Resource2();
Resource3 res3 = new Resource3();
try ( res1; res2; res3) {
;; // pass (아무것도 하지 않는다)
} catch(Exception e) {
e.printStackTrace();
} // try-with-resources
} //main
} // end class
- 결과창
resource3 > 2 > 1 순서로 자원 해제
- AutoCloseable 인터페이스를 implements 하지않으면 나타나는 에러
TDD(Test Driven Development)
- 테스트 주도 설계
- 테스트를 먼저 만들고 테스트를 통과하기 위해 코드를 짜며 실제 서비스될 코드를 작성하는 개발 방법론 중 하나이다.
- 장점 : 객체지향적인 코드 개발 가능, 설계 수정 및 디버깅 시간 단축, 유지보수 용이, 오버 엔지니어링 방지 등
- 단점 : 개발 시간 증가, 어려움
JUnit
- 자바 프로그래밍 언어용 유닛 테스트 프레임워크
1. JUnit5 -> "JUnit Jupyter"로 이름이 바뀜
2. 사용가능한 어노테이션이 많이 증가
3. 테스트 클래스로부터, 테스트 객체를 생성하는 방법이 2가지로 바뀜
(1) PER_CLASS (테스트 객체 1개만 생성)
(2) PER_METHOD (테스트 메소드 수행시마다, 객체 생성)
4. 테스트 메소드의 수행 순서를 결정할 수 있게됨 (@TestMethodOrder)
참고)) import org.junit.jupiter.api.TestMethodOrder;
@Log4j2
@NoArgsConstructor
// 타입선언부 위에, 아래와 같이 기본적인 2개의 어노테이션을 설정
@TestInstance(Lifecycle.PER_CLASS) //또는 @TestInstance(Lifecycle.PER_METHOD)
@TestMethodOrder(OrderAnnotation.class)
public class JUnit5_Template {
// 사전처리 메소드 (@BeforeAll, @BeforeEach)는 선택
@BeforeAll
void beforeAll() {
log.trace("beforeAll() invoked.");
}
@BeforeEach
void beforeEach() {
log.trace("beforeEach() invoked.");
}
@Test
@Order(2) // 테스트 메소드의 실행순서 지정
@DisplayName("덧셈 메소드의 기능을 테스트 합니다.")
@Timeout(value=1, unit=TimeUnit.SECONDS)
void contextLoad1() {
log.trace("contextLoad1() invoked.");
}
@Test
@Order(1)
@DisplayName("곱셈 메소드의 기능을 테스트 합니다.")
@Timeout(value=1, unit=TimeUnit.SECONDS)
void contextLoad2() {
log.trace("contextLoad2() invoked.");
}
// 사후처리 메소드 (@AfterAll, @AfterEach)는 선택
@AfterEach
void afterEach() {
log.trace("afterEach() invoked.");
}
@AfterAll
void afterAll() {
log.trace("afterAll() invoked.");
}
} //class
beforeAll()과 afterAll() 은 한번만 수행!! (사전/사후 처리)
Each()는 per test마다 반복된다.
< 어노테이션 설명 >
@TestInstance(Lifecycle.PER_CLASS) 또는 @TestInstance(Lifecycle.PER_METHOD)
- 테스트 인스턴스의 생성기준을 설정
@TestMethodOrder(OrderAnnotation.class)
테스트 클래스 안에 여러개의 테스트 메소드가 있을 때,
테스트 클래스의 전체 테스트 메소드 수행시
각 메소드의 수행순서를 @Order 어노테이션을 통해 실행순서를 지정할 때 사용함
@Test
@Order(2) // 실행순서 지정
@DisplayName("contextLoad1")
@Timeout(value=1, unit=TimeUnit.SECONDS)
void contextLoad1() {
log.trace("contextLoad1() invoked.");
}
@Test
@Order(1)
@DisplayName("contextLoad2")
@Timeout(value=1, unit=TimeUnit.SECONDS)
void contextLoad2() {
log.trace("contextLoad2() invoked.");
}
결과 --> contextLoad2()가 먼저 실행됨.
* Class 객체를 얻어내는 방법
1. 타입명.class
2. 참조변수명.getClass()
3. Class.forName(문자열타입의 FQCN)