일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 게시판프로젝트
- 시큐리티
- Spring
- request영역
- 게시판댓글수
- ResponseEntity
- 회원정보
- session영역
- Security
- jsp
- 게시판댓글
- SCOPE
- RPTLANFTN
- page영역
- 댓글수처리
- 스프링회원정보수정
- 회원정보수정
- 스프링
- application영역
- 스프링시큐리티
- 내장객체
- Today
- Total
코코무의 코딩캔버스
[Spring] 의존성 주입 테스트 본문
※ 교재 [코드로 배우는 스프링 웹 프로젝트 - 구멍가게 코딩단]을 바탕으로 작성되었습니다.
스프링의 개념과 특징들을 알아보았습니다.
그럼 이제 스프링의 가장 큰 특징인 의존성 주입 기능을 작성하고 테스트해 보겠습니다.
사용할 클래스: Restaurant.java / Chef.java
* Restaurant 클래스에 Chef 클래스를 주입할 것입니다(Restaurant 클래스가 Chef 타입의 객체를 필요로 함).
왜냐하면 식당에 요리사가 있어야 장사를 할 수 있기 때문이지요.
스프링에서 의존성 주입을 구현하는 방법은 총 두 가지입니다.
1. 생성자를 이용한 주입
2. Setter 메서드를 이용한 주입
설정 방식은 주로 XML 또는 어노테이션(@)으로 처리합니다.
0. pom.xml에 라이브러리 추가
예제에서는 lombok으로 setter 메서드를 자동으로 구현하도록 하겠습니다(생성자는 다음 기회에 모시겠습니다).
lombok을 사용하기 위해서는 pom.xml에 lombok 라이브러리를 추가하고, spring-test 라이브러리를 이용합니다.
1. 예제 클래스 생성
src/main/java/org.zerock.sample/Chef.java
@Component //해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //lombok의 setter를 생성하는 기능, 생성자 등을 자동 생성하는 역할
public class Chef {}
src/main/java/org.zerock.sample/Restaurant.java
@Component //해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //lombok의 setter 기능, 생성자 등 자동 생성하는 역할(setChef() 컴파일 시 생성)
public class Restaurant {
@Setter(onMethod_ = @Autowired)
public Chef chef; //Restaurant에 Chef를 주입 받음(R은 C 타입의 객체를 필요로 함)
}
@Component: 스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시하는 어노테이션
@Data: Lombok의 setter를 생성하는 기능과 생성자, toString() 등을 자동으로 생성하도록 하는 어노테이션
@Setter: 자동으로 setChef()를 컴파일 시 생성
onMethod_: 생성되는 setChef()에 @Autowired을 추가하도록 함
@Autowired: 지금 밑에 쓴 객체가 우리 클래스에 필요해‼️
2. XML을 이용하는 의존성 주입 설정(빈 설정)
스프링은 클래스에서 객체를 생성하고 객체들의 의존성에 대한 처리 작업까지 내부에서 모든 것이 처리됩니다.
스프링에서 관리되는 객체를 빈(Bean)이라고 하는데 root-context.xml에서 빈에 대한 설정을 할 수 있습니다.
'콩이 나려면 식물의 뿌리가 필요하니까'라고 생각하면 썰렁하니 좋습니다.
root-context.xml에서 Namespace 탭에 들어가 'context' 항목을 체크해 줍니다.
그리고 Source 탭에서 코드를 추가해야 합니다.
beans xmlns 태그에서 context에 대한 부분을 추가해야 하는데, 새삼 책에 있는 내용이라 여기에다 써도 되는지 모르겠습니다.
무튼 그리고
<context:component-scan base-package="org.zerock.sample">
</context:component-scan>
component-scan은 위 두 개의 클래스에서 사용했던 @Component 어노테이션을 스캔합니다.
위에서 @Component 어노테이션은 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시하는 역할이라고 했었습니다.
component-scan 뒤에 패키지 이름을 쓰면, 그 패키지 안에서 사용된 어노테이션을 스캔하여
'너 우리 (스프링)파냐?' 하고서 관리에 들어가게 된 것입니다.
xml 파일을 저장한 뒤 Bean Graph 탭을 들어가 보면, Restaurant와 Chef 객체 콩들이 귀엽게 생겨난 것을 볼 수 있습니다.
이제는 Restaurant 클래스와 Chef 클래스 그리고 root-context.xml이 어떻게 동작하는지 좀 더 자세히 살펴봅시다.
코난과도 같이 일이 발생한 시간 순서대로 짚어가 보겠습니다.
미래소년 코난을 떠올리셨다면...유감입니다.
1. 스프링 프레임워크가 시작되면 가장 먼저는 스프링이 사용하는 메모리 영역을 만듭니다.
그 메모리 영역을 스프링에서는 ApplicationContext라고 하고 이것(마저)도 하나의 객체입니다.
2. 스프링은 스스로 객체 생성 및 관리에 대한 설정을 해야 합니다. 그 설정을 하는 곳이 바로 root-context.xml입니다.
3. root-context.xml에 설정되어 있는 <context:component-scan> 태그의 내용을 통해서 'org.zerock.sample' 패키지를 스캔합니다.
4. 해당 패키지에 있는 클래스들 중에서 스프링이 사용하는 @Component 어노테이션이 존재하는 클래스의 인스턴스를 생성합니다.
5. Restaurant 객체는 Chef 객체가 필요하다는 어노테이션 설정(@Autowired)이 있기 때문에 스프링은 Chef 객체의 레퍼런스를 Restaurant 객체에 주입합니다.
이 모든 일은 ApplicationContext에서 일어납니다.
이렇게 코드를 작성했으면, 잘 동작하는지 테스트가 필요합니다.
이름은 Junit 테스트.
src/test/java 폴더 안에 org.zerock.sample.SampleTests 클래스를 만들어주겠습니다.
이 클래스는 spring-test 모듈을 이용하여 간단하게 스프링을 가동시키고 위의 동작들이 일어나게 합니다.
@RunWith(SpringJUnit4ClassRunner.class) //현재 테스트 코드가 스프링을 실행하는 역할을 할 것
//지정된 클래스나 문자열을 이용해서 필요한 객체들을 스프링 내로 객체로 등록함(스프링의 빈으로 등록됨), 문자열은 root-context.xml의 경로를 지정함
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j2 //lombok을 이용해서 로그를 기록하는 logger를 변수로 생성함
public class SampleTests {
@Setter(onMethod_ = @Autowired) //Restaurant 타입 객체 주입
private Restaurant restaurant;
@Test //JUnit에서 테스트 대상을 표시함
public void testExist() {
assertNotNull(restaurant); //restaurant 변수가 null이 아니어야만 테스트 성공함
log.info(restaurant);
log.info("--------------------------------------");
log.info(restaurant.getChef());
}
}
@Runwith(SpringJUnitClassRunner.class): 현재 테스트 코드가 스프링을 실행하는 역할을 할 것
@ContextConfuiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml"): 지정된 클래스나 문자열을 이용해서 필요한 객체들을 스프링 내로 객체로 등록함
@Log4j2: lombok을 이용하여 로그를 기록하는 logger를 변수로 생성함
@Setter: 클래스 타입의 객체 주입
@Test: JUnit에서 테스트 대상을 표시함
assertNotNull: 변수가 null이 아니어야만 테스트에 성공함
무사히 테스트를 마쳤습니다. 그럼 이제 테스트를 분석해볼까요?
첫째, 일전에 계속해서 사용했던 new Restaurant( )로 Restaurant 클래스에서 객체를 생성한 적이 없는데도
필드 선언만으로도 객체가 만들어졌습니다.
이는, 스프링은 관리가 필요한 객체를 어노테이션 등을 이용하여 객체를 생성하고 관리하는
<컨테이너> 또는 <팩토리>의 기능을 가지고 있기 때문입니다.
스프링을 객체 공장으로 쉽게 이해해도 될 것 같습니다.
그리고 객체를 만들고 관리하는 기능들을 공장의 로봇과 근무자라고 할 수 있겠지요.
둘째, Restaurant 클래스의 @Data 어노테이션으로 Lombok을 이용해서 여러 메서드가 만들어졌습니다.
Lombok은 자동으로 getter/setter 등을 만들어 주는데 스프링은 생성자 주입 또는 setter 주입을 이용해서 동작합니다.
Lombok을 통해서 getter/setter 등을 자동으로 생성하고
onMethod 속성을 이용해 작성된 setter에 @Autowired 어노테이션을 추가합니다.
셋째, Restaurant 객체의 Chef 인스턴스 변수(멤버 변수)에 Chef 타입의 객체가 주입되어 있습니다.
정리하자면 다음과 같습니다.
1) 테스트 코드가 실행되기 위해 스프링 프레임워크가 동작했고
2) 동작하는 과정에서 필요한 객체들이 스프링에 등록되었고
3) 의존성 주입이 필요한 객체는 자동으로 주입이 이루어짐
코드에 사용된 어노테이션들을 구분하면 다음과 같습니다.
Lombok 관련 어노테이션 | Spring 관련 어노테이션 | 테스트 관련 어노테이션 |
@Setter @Data @Log4j2 |
@Autowired @Component |
@RunWith @ContextConfiguration @Test |
[Lombok 관련 어노테이션]
1. @Setter
1) value
- 접근 제한 속성
- 기본값: lombok.AccessLevel.PUBLIC
2) onMethod
- setter 메서드 생성 시 메서드에 추가할 어노테이션을 지정함
3) onParam
- setter 메서드의 파라미터에 어노테이션을 사용하는 경우 적용
2. @Data
1) @ToString, @EqualsAndHashCode, @Getter/Setter, @RequiredArgsConstructor를 모두 결합한 형태
2) 세부적인 설정이 필요 없을 때 주로 사용
3. @Log4j2
1) 로그 객체 생성
2) 존재하지 않을 경우 @Log 사용 가능
[Spring 관련 어노테이션]
1. @Component
해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시하는 어노테이션
2. @Autowired
스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입하라는 표시
[Test 관련 어노테이션]
1. @ContextConfiguration
스프링이 실행되면서 어떤 설정 정보를 읽어 들여야 하는지 명시
속성으로 locations를 사용하여 문자열의 배열로 xml 설정 파일을 명시하거나 classes 속성으로 @Configuration이 적용된 클래스를 지정해 줄 수도 있습니다.
2. @RunWith
테스트 시 필요한 클래스를 지정합니다. 스프링은 SpringJUnit4ClassRunner 클래스가 대상이 됩니다.
3. @Test
junit에서 해당 메서드가 junit 상에서 단위 테스트의 대상인지 알려줍니다.
이번 포스팅에서는 스프링의 가장 큰 특징인 의존성 주입에 대해 다뤄보았습니다.
총총.🐰
'Spring' 카테고리의 다른 글
[Spring] AOP와 트랜잭션(@Transactional) (0) | 2024.03.08 |
---|---|
[Spring] AOP에 대하여 (0) | 2024.03.07 |
[Spring] 댓글 처리(REST와 Ajax...스압주의) (0) | 2024.03.07 |
[Spring] MyBatis의 페이징 처리 (0) | 2024.03.05 |
[Spring] 스프링의 개념과 특징 총정리 (0) | 2024.02.22 |