일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 비트마스킹
- 이영직
- 오블완
- react
- 자료구조
- 구현
- multipart upload
- React Natvive
- 창의충전소
- 백준 1992
- BFS
- web view
- springboot
- 버튼 활성화
- 완전탐색
- 티스토리챌린지
- 원복
- React Native
- 노마드코더
- 상속 관계 매핑
- apk파일 추출
- bfs dfs
- Navigation
- 경우의 수
- 폴더구조
- 해외 대외활동
- 휴대폰 기기
- FlatList
- ReactNative
- Project Bee
- Today
- Total
유미의 기록들
[최종 프로젝트] Reflection을 이용한 테스트 코드 본문
💡 배경
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class SaveLectureRequest {
@NotBlank(message = "제목을 작성해 주세요")
private String title;
@NotBlank(message = "설명을 작성해 주세요")
private String description;
@NotBlank(message = "추천인을 작성해 주세요")
private String recommend;
@NotNull(message = "카테고리를 작성해 주세요")
private Category category;
@NotNull(message = "난이도를 작성해 주세요")
private Level level;
@NotNull(message = "가격을 작성해주세요")
private BigDecimal price;
}
LectureService 테스트 코드를 작성하면서 `SaveLectureRequest`객체를 생성할 때, `@AllArgsConstructor`가 `AccessLevel.PROTECTED`로 설정되어 있어서 외부에서 직접 접근할 수 없었다. 테스트 코드를 위해 접근 제어자를 public으로 변경하거나 정적 팩토리 메소드를 추가한다면 코드의 복잡성을 증가시키고 유지보수를 어렵게 할 수 있어서 Java의 Reflection 기능을 사용하여 실제 비즈니스 로직을 수정하지 않고 테스트를 작성하려고 한다.
📝 Reflection
힙 영역에 로드된 Class 타입의 객체를 통해, 런타임에 접근 제어자 상관없이 원하는 클래스의 정보에 접근해서 수정할 수 있도록 지원하는 API
Java에서는 `java.lang.reflect` 패키지를 통해 Reflection을 사용할 수 있으며, 이를 통해 클래스나 객체의 구조에 대한 정보를 동적으로 가져오고 조작할 수 있다
조작할 수 있는 기능들
- 클래스의 이름, 접근제어자, 부모 클래스, 구현 인터페이스 등 확인 가능
- 생성자, 메서드, 필드에 접근하고 호출 가능
- 생성자를 이용하여 객체를 동적으로 생성하거나 메서드 호출 가능
- 접근 제어자 관계 없이 필드나 메서드에 접근 가능
장점
- 컴파일 시점에 클래스나 메서드에 대해 알지 못해도, 런타임에 해당 객체를 다룰 수 있어 동적 프로그래밍이 가능
- 많은 프레임워크(Spring, Hibernate 등)가 리플렉션을 사용하여 객체의 의존성을 주입하거나 설정 정보를 동적으로 적용
- 접근 제어자가 private인 필드나 메서드에 접근해서 조작 가능
단점
- 일반 메서드 호출보다 느리며, 많이 사용하면 성능에 영향을 줄 수 있음
- 캡슐화가 깨질 위험성이 존재함
- 컴파일 시점에 체크되지 않고 런타임에 발생하는 오류가 많아 예외가 발생할 가능성이 높음
프레임워크에서의 활용
- 스프링 프레임워크 : 의존성 주입, AOP, 이벤트 처리 등이 리플렉션을 기반으로 동작한다 (`@Autowired`이 적용된 생성자를 찾아서 자동으로 의존성 주입)
- 하이버네이트 : 리플렉션을 사용해 객체와 데이터베이스 테이블 간의 매핑을 동적으로 처리한다
- JUnit : 리플렉션을 활용해서 테스트케이스를 동적으로 로드하고 실행한다 (`@Test`이 달린 메소드를 찾아내 테스트를 수행함)
Reflection은 강력한 기능을 제공하지만, 잘못 사용하면 프로그램의 안정성에 영향을 줄 수 있기 때문에 필요한 상황에서만 제한적으로 사용하고, 보안 측면을 항상 고려해서 사용해야 한다.
💻 코드 적용
생성자에 접근하여 객체 생성
Constructor<SaveLectureRequest> constructor = SaveLectureRequest.class.getDeclaredConstructor(
String.class, String.class, String.class, Category.class, Level.class, BigDecimal.class
);
constructor.setAccessible(true);
saveLectureRequest = constructor.newInstance(
"테스트 강의",
"설명",
"추천인",
Category.WEB_DEV,
Level.EASY,
new BigDecimal(100000)
);
생성자에 접근하기 위해서는 Class 객체를 통해 해당 생성자의 Constructor 객체를 얻어야 한다
`getDeclaredConstructor()` : 클래스에 선언된 모든 생성자에 접근할 때 사용
`setAccessible(true)` : 접근 제한을 해제
`newInstance()` : 객체를 생성
엔티티 필드 접근 및 수정
Field lectureField = Lecture.class.getDeclaredField("approval");
lectureField.setAccessible(true);
lectureField.set(lecture, Approval.APPROVED);
필드에 접근하기 위해서 Class 객체를 통해 해당 필드의 Field 객체를 얻어야 한다
`getDeclaredField()`를 통해 필드에 접근하여 Lecture엔티티의 approval필드를 `set()` 메소드를 사용하여 Approval.APPROVED로 상태를 변경함
'대외활동 기록 > 내일배움캠프' 카테고리의 다른 글
[최종 프로젝트] CDN 적용하여 강의 컨텐츠 조회 성능 최적화 (1) | 2024.11.12 |
---|---|
[최종 프로젝트] SpringBoot 프로젝트 EC2 배포 (2) | 2024.11.11 |
[최종 프로젝트] AWS Multipart Upload로 대용량 파일 업로드 (0) | 2024.11.09 |
[최종 프로젝트] 생성자 대신 정적 팩토리 메서드 (0) | 2024.11.08 |
[최종 프로젝트] Entity 계층 구조에 따른 상속 관계 매핑 (0) | 2024.11.07 |