프로젝트 진행중 한동안 수업을 진행하여
실질적인 프로젝트 구현은 내일부터 할 것 같습니다
앞으로도 수업과 병행하여 배우는 동시에 구현해야해서
힘들지만 프로젝트를 완성시키기 위해 달리겠습니다
0. 백엔드 개발자의 업무
- 백엔드 개발자의 주된 업무 : 서버 측 어플리케이션을 개발하는 일
- 과제할당 -> 과제분석 -> 개발 -> 테스트 -> QA 및 버그 수정 -> 배포 -> 유지보수
1. 웹 서비스의 동작 원리
1) 클라이언트-서버 구조
웹브라우저 -----요청-----> 웹서버
<-----응답-----
클라이언트 서버
웹서비스는 클라이언트의 요청에 따른 서버의 응답으로 동작한다
클라이언트(Client) : 서비스를 사용하는 프로그램 또는 컴퓨터
서버(Server) : 서비스를 제공하는 프로그램 또는 컴퓨터
2) IP주소와 포트
IP(아이피) : 인터넷에서 컴퓨터 또는 기기들이 서로 식별하고 통신하기 위한 주소 (특정 집의 주소)
PORT(포트) : 네트워크 서비스를 구분하는 번호 (집 안에 있는 방)
프로토콜 서비스내용 포트번호
HTTP 웹서비스 80
HTTPS SSL을 적용한 웹서비스 443
FTP 파일 전송 서비스 21
SSH,SFTP 보안이 강화된 TELNET,FTP 서비스 22
TELNET 원격 서버 접속 서비스 23
SMTP 메일 전송 서비스 25
3) localhost:8080/index.html의 의미
localhost : 실행중인 서버의 주소 중 내 컴퓨터를 의미
= 127.0.0.1
8080 포트번호를 의미, 톰캣이 8080번에서 수행되고 있다는 의미
4) API, 라이브러리, 프레임워크 *********
API 어플리케이션 간에 상호작용을 가능하게 해주는 인터페이스
라이브러리 어플리케이션 개발에 필요한 기능인 클래스, 함수 등을 모아놓은 코드의 모음
프레임워크 소프트웨어 개발을 수월하게 하기 위한 소프트웨어 개발 환경
Frame(틀) + Work(일하다) => 일하기 위한 틀을 제공한다
2. 스프링부트(Spring boot)
자바 웹 프로그램을 더욱 쉽고 빠르게 만들기 위한 자바의 웹 프레임워크
스프링 프레임워크에 톰캣 서버를 내장하고 여러 편의 기능들을 추가
- 톰캣 서버 : 클라이언트의 요청을 해석하여 그에 맞는 자바크로그램을 실행한 후 그 결과를
응답해주는 웹 어플리케이션 서버
0) 웹 프레임워크
웹 프로그램을 만들기 위한 스타터 키트
자바로 만든 웹 프레임워크 중 하나가 스프링이다
1) 스프링의 등장
엔터프라이즈 어플리케이션은 대규모의 복잡한 데이터를 관리하는 어플리케이션을 의미
엔터프라이즈 어플리케이션은 소프트웨어 분야가 발전하면서 점점 복잡해졌고
많은 사용자의 요청을 동시에 처리해야 하므로 서버성능, 안정성, 보안이 매우 중요해짐
외부적인 부분과 비즈니스 로직까지 신경써서 개발하기엔 개발자들의 어려움이 있음
2003년 6월 스프링 프레임워크가 등장(서버성능, 안정성, 보안을 매우 높은 수준으로 제공하는 도구)
=> 개발자는 기능개발에 집중가능
2) 스프링 단점
설정이 매우 복잡하다는 단점이 존재함
스프링 개발팀에서 단점을 인식하여 보완 => 스프링부트를 출시함(2013년 4월 0.5.0.M6 버전 첫 공개)
개발자가 비즈니스 로직 개발에만 집중할 수 있도록 만들어준 도구
3) 스프링부트의 주요 특징
- 톰캣, 제티, 언더토우 같은 웹 어플리케이션이 내장되어 있어 따로 설치하지 않아도 독립적으로 실행 가능
- 빌드 구성을 단순화하는 스프링부트 스타터를 제공
- XML 설정하지 않고 자바코드로 모두 작성할 수 있음
- jar를 이용하여 자바 옵션만으로도 배포 가능
- 어플리케이션의 모니터링 및 관리도구인 스프링 액츄에이터를 제공
4) 스프링과 스프링부트 특징 비교
(1) 구성의 차이
스프링은 어플리케이션 개발에 필요한 환경을 수동구성, 정의
스프링부트는 스프링 코어와 스프링 MVC의 모든 기능을 자동으로 로드하므로
수동으로 개발환경을 구성할 필요가 없음
(2) 내장 WAS 유무
톰캣과 같은 WAS에서 배포됨
스프링은 별도 수동으로 설정함
스프링부트 내장형 서버 존재함
스프링 스프링부트
목적 엔터프라이즈 어플리케이션 개발을 스프링의 개발을 더 빠르고 쉽게 하기
더 쉽게 만들기
설정파일 개발자가 수동으로 구성 자동 구성
xml 일부 파일은 xml로 직접 생성하고 관리 사용하지 않음
인메모리 데이터베이스 지원 지원하지 않음 인메모리 데이터베이스 자동설정 지원
서버 프로젝트를 띄우는 서버(ex: 톰캣)를 내장형 서버를 제공해 별도의
별도로 수동설정 설정 필요없음
3. 스프링 프레임워크
스프링은 자바 기반 웹 어플리케이션 개발을 쉽게 할 수 있도록 돕는 프레임워크
POJO 기반으로 간단한 자바 객체를 사용하는 방식으로 개발
의존성 주입, 트랜잭션 관리, MVC 구조 등 다양한 기능을 지원
특히 유지보수에 유리하고 다른 프레임워크와의 연동이 매우 뛰어남
- POJO(Plain Old Java Object) 기반
스프링은 기존의 복잡한 프레임워크들과는 달리 순수 자바 객체로 개발을 할 수 있어 가볍고 유연하다
4. 스프링부트를 배워야 하는 이유
- 스프링부트는 튼튼한 웹 프레임워크이다
보안기능을 기본적으로 잘 막아준다
sql 인젝션(악의적인 sql을 주입하여 공격하는 방법),
XSS(Cross-site scripting) : 자바스크립트를 삽입해서 공격하는 방법,
CSRF(Cross-site Request Forgery) : 위조된 요청을 보내는 공격방법,
Clickjacking(클릭재킹) : 사용자가 의도하지 않은 클릭을 유도하는 공격방법
- 스프링부트에는 여러 기능이 준비 되어있다
2012년에 등장해 10년 이상을 많은 개발자들이 사용하여 기능이 정리되어 있는 웹 프레임웤
- 스프링부트는 WAS가 필요없다
- 스프링부트는 설정이 쉽다
=> 스프링부트는 스프링 프레임워크의 복잡한 설정을 단순화 시켜 개선한 것
개발환경 설정을 간소화, 웹 어플리케이션 서버를 내장
5. 제어의 역전(IoC)과 의존성 주입(DI)************************개중요
1) IoC(Inversion Of Control) : 제어의 역전
자바 코드를 작성해 객체를 생성 시 객체가 필요한 곳에서 직접 생성함
객체의 입장에서 사용할 다른 객체를 직접 생성하여 제어한다는 것이 일반적인 제어흐름 이다
제어의 역전은 이 흐름을 반대로 뒤집은 것으로 객체가 사용하는 다른 객체를 직접 생성하지 않아도 되고
자기 자신도 어디서 사용되는지 알 수 없다
특별한 권한을 가진 다른 객체에 의해 결정되고 만들어진다
IoC 컨테이너 : 스프링에서 객체 생성, 관리, 의존성 주입을 담당하는 주요 컴포넌트
IoC 컨테이너는 논리적인 구조이다
BeanFactory는 가장 기본적인 IoC 컨테이너 기능을 제공
ApplicationContext 업그레이드 되어 추가기능을 제공
제어의 역전은 다른 객체를 직접 생성하거나 제어하는 것이 아니라
외부에서 관리하는 객체를 가져와 사용하는 것을 의미한다
제어의 역전을 적용하면 제어권이 A클래스에서 스프링 컨테이너로 넘어가고
이제 A클래스는 B객체를 직접 생성하지 않고
스프링 컨테이너가 생성한 객체를 주입받아 사용한다
- IoC를 적용하면 코드는 유연하고 객체간의 결합도가 낮아진다
2) DI(Dependency Injection) : 의존성 주입
스프링의 핵심 기능이며, 클래스들 간의 의존성을 낮춰 코드 재사용성을 높인다
DI는 어떤 클래스가 다른 클래스에 의존한다는 의미
@Autowired 어노테이션은 스프링 컨테이너에 있는 빈이라는 것을 주입하는 역할을 한다
- 빈(Bean) : 스프링 컨테이너에서 관리하는 객체를 의미
※ 기존의 자바 코드는 클래스 A에서 B객체를 쓰고 싶은 경우 직접 생성했지만 스프링의 경우
클래스 A에서 B객체를 쓰고 싶은 경우 객체를 직접 생성하는 것이 아닌 스프링 컨테이너에서 객체를 주입받아 사용
※ IoC/DI 개념은 스프링의 핵심개념!!!!(중요) ************************
※ 개방폐쇄의 원칙(OCP : Open-Closed Principle)
기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계 되어야 한다는 원칙
보통 OCP를 확장에 대해서는 개방적(open)이고 수정에 대해선 폐쇄적(closed)이어야 한다는 의미로 정의
<기존의 클래스 호출방식>
class Service {
public void serve() {
System.out.println("Service is serving...");
}
}
class Client {
private Service service;
public Client() {
// Client가 Service 객체를 직접 생성
service = new Service();
}
public void doSomething() {
service.serve();
}
}
<제어의 역전 방식>
class Service {
public void serve() {
System.out.println("Service is serving...");
}
}
class Client {
private Service service;
// 의존성을 외부에서 주입받음
public Client(Service service) { //여기
this.service = service; //여기 차이 잘 보셈
}
public void doSomething() {
service.serve();
}
}
3) 빈과 스프링 컨테이너
스프링 컨테이너
- 스프링은 스프링 컨테이너를 제공한다
- 스프링 컨테이너는 빈을 생성하고 관리한다
- 즉, 빈이 생성되고 소멸되기 까지의 생명주기를 스프링 컨테이너가 관리한다
- 개발자가 어노테이션을 사용해 빈을 주입받을 수 있게 DI를 지원하기도 한다
빈
- 스프링 컨테이너가 생성하고 관리하는 객체
- 스프링은 빈을 스프링 컨테이너에 등록하기 위해 xml 파일 설정, 어노테이션 추가 등의 방법을 제공
- @Component, @Configuration등 어노테이션을 사용하면 이 클래스를 스프링 컨테이너가 빈으로 관리한다
4) 관점지향 프로그래밍(AOP : Aspect Oriented Programming)
- 공통되고 반복되는 관심사(기능 등)를 분리하여 모듈화 한다
- 프로그래밍에 대한 관심을 핵심 관점, 부가 관점으로 나누어서 관심 기준으로 모듈화 하는 것을 의미한다
ex) 계좌이체, 고객관리 프로그램이 있다, 각 프로그램에는 로직과 여러 데이터를 관리하기 위한
데이터베이스 연결로직이 포함된다.
핵심관점은 계좌이체, 고객관리 로직이고 부가관점은 로깅, 데이터페이스 연결로직이다.
- 관심사를 분리하게 되면 개발자는 핵심로직에만 집중하여 코드를 작성할 수 있으며 유지보수에 유리하다
- 분리한 기능을 관점(Aspect)이라고 한다
관심사를 분리한다는 것은 여러 기능에서 중복되는 코드를 분리하는 것을 의미한다
즉, 어려 종단 관심사(주요로직)에서 반복되는 횡단 관심사(부가기능)를 분리하는 것이다
JDBC => 회원가입 / 로그인 (종단 관심사)
횡단 관심사 => DBConnecter 객체를 만들어서 사용한다
5) 이식 가능한 서비스 추상화(PSA : Portable Service Abstraction)
ex) 스프링에서 데이터베이스에 접근하기 위한 기술로 JPA, MyBatis, JDBC 등이 있는데
어떤 기술을 사용하든 일관된 방식으로 데이터베이스에 접근하도록 인터페이스를 지원한다
6) 트랜잭션 관리
XML이나 어노테이션으로 트랜잭션 관리를 쉽게 설정할 수 있다
7) 편리한 MVC 구조
스프링은 자체적으로 MVC 프레임워크를 제공하여 개발자가 불필요한 코드를 줄일 수 있게 도와준다
Model : 비즈니스 로직에 필요한 데이터를 담는 그릇 DTO, VO
해당 데이터를 가져오는 DAO
View : 동적으로 화면을 만드는 jsp
Controller : 비즈니스 로직을 작성하고 Model과 View사이에서 연결하는 용도
web.xml, front controller를 우리가 작성하지 않아도 자동으로 매핑되는 기능을 지원해 주므로
개발자는 불필요한 코드를 줄일 수 있다
8) WAS에 종속적이지 않음
특정 WAS만 사용 가능한 것이 아니라 다양한 서버에서 동작할 수 있다
WAS 없이도 독립적인 테스트가 가능하여 테스트가 쉽고 빠르다
9) 단위테스트
WAS를 실행하지 않고 독립적으로 테스트하는 방법
+) 정리
IoC 제어의 역전 객체의 생성과 관리를 개발자가 하는 것이 아니라
프레임워크가 대신 해주는것
DI 의존성 주입 외부에서 객체를 주입받아 사용하는 것
AOP 관점지향프로그래밍 프로그래밍을 할 때 핵심관점과 부가관점을 나누어서 개발하는 것
PSA 이식 가능한 서비스 추상화 어느 기술을 사용하던 일관된 방식으로 처리하는 것
-----------------------------------------------------------------------------------------------------
day80
스프링부트 프로젝트 구조 -> 의존성 주입(DI) -> 테스트코드 -> My Batis
1. 스프링부트 프로젝트 구조
1) src/main/java 디렉터리 : 자바 파일을 저장하는 공간
cohttp://m.mysite.app 패키지
컨트롤러는 URL 요청을 처리하고 폼은 사용자의 입력을 검증한다
DTO, 엔티티, 서비스 파일은 데이터베이스를 처리하기 위해 필요한 파일이다
+) 패키지 구조
controller 패키지 웹 요청을 처리하는 컨트롤러 클래스들이 위치
@RestController, @Controller 어노테이션이 붙은 클래스들
service 패키지 비즈니스 로직을 처리하는 서비스 클래스들이 위치
@Service 어노테이션을 사용하여 서비스 계층을 구성하며
컨트롤러와 데이터 접근 계층(Repository) 사이에서 중간역할을 함
repository 패키지 데이터베이스와 상호작용하는 레포지토리 인터페이스들이 위치
@Repository 어노테이션을 사용하며 MyBatis, JPA 기술을 사용하여 데이터 처리
domain or model 패키지 도메인 객체나 엔티티 클래스들이 위치함
데이터베이스 테이블과 매핑되는 엔티티 클래스를 정의하거나
DTO(Data Transfer Object)를 포함할 수 있음
config 패키지 스프링부트 어플리케이션의 설정과 관련된 클래스들이 위치함
@Configuration 어노테이션을 사용하여 설정 클래스를 정의
2) src/main/resources 디렉터리 : 자바 파일을 제외한 HTML, CSS, Javascript, 환경 파일 등을 저장하는 공간
templates 디렉터리 : 템플릿 파일은 자바 코드를 삽입할 수 있는 HTML 형식의 파일을 저장
static 디렉터리 : css, js, img 파일 등을 저장
Application.properties 파일 : 프로젝트의 환경변수, 데이터베이스 등의 설정을 이 파일에 저장
3) src/test/java 디렉터리 : 프로젝트에서 작성한 파일을 테스트하는 코드를 저장하는 공간
JUnit 과 스프링부트의 테스트 도구를 사용하여 서버를 실행하지 않은 상태에서
해당 디렉터리에 작성한 코드를 테스트 할 수 있다
4) 루트 디렉터리 > build.gradle 파일 : Gradle 빌드 시스템을 사용하는 경우 프로젝트 의존성 및 빌드설정 정의
그레이들(Gradle) 이 사용하는 환경파일
그레이들은 그루비(Groovy)를 기반으로 한 빌드 도구로 Ant, Maven과 같은
이전 세대의 단점을 보완하고 장점을 취합하여 만들었다
2. 의존성 주입(DI)
의존성 주입이란 객체가 필요로 하는 의존 객체(Dependency)를 외부에서 주입해 주는 방식
클래스 내부에서 직접 객체를 생성하는 대신, 외부에서 생성한 객체를 전달받아 사용함으로써
객체간의 결합을 느슨하게 만들어 준다
*스프링 컨테이너는 객체를 관리하고 필요한곳에 자동으로 주입해 준다
클래스 위 @Component 사용으로 스프링 컨테이너가 관리하는 Bean 으로 등록
메소드 위 @AutoWired 사용으로 스프링 컨테이너가 관리하는 클래스를 자동으로 주입
*테스트 클래스에는 @SpringBootTest 를 꼭 붙혀야한다
*클래스 위 @Data는 겟터셋터, 생성자, toString 등 자동 설정해줌
build.Gradle 파일에서 사용되는 의존성을 관리하는 부분이고
특정 라이브러리나 플러그인을 프로젝트에 추가하거나 특정 상황에서만 사용할 수 있도록 한다
*************
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
//thymeleaf 템플릿 엔진을 사용하기 위한 의존성
implementation 'org.springframework.boot:spring-boot-starter-web'
//Spring Web 관련 기능을 포함한 스타터
//스프링 MVC를 기반으로 한 웹 어플리케이션 개발을 지원하고 REST API를 구현할 수 있게 해준다
//내장된 Tomcat 서버가 포함되어 있음
compileOnly 'org.projectlombok:lombok'
//java 클래스에서 반복적인 코드를 줄여주는 도구
developmentOnly 'org.springframework.boot:spring-boot-devtools'
//개발시 어플리케이션의 개발 생산성을 높이는 도구
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
//@ConfigurationProperties 를 처리하는데 사용
//자동으로 설정 클래스를 기반으로 한 메타데이터를 생성하여 IDE에서 지원하는 자동완성 기능 사용 가능
annotationProcessor 'org.projectlombok:lombok'
//lombok 어노테이션을 처리하는 컴파일러 플러그인
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//테스트 관련 기능을 포함한 스타터
//단위테스트 및 통함테스트를 쉽게 작성할 수 있다
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
//JUnit 플랫폼 런처로 테스트를 실행하는데 필요한 런타임 구성요소
implementation 'org.projectlombok:lombok:1.18.28'
tationProcessor 'org.projectlombok:lombok:1.18.28'
testImplementation 'org.projectlombok:lombok:1.18.28'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.28'
}
implementation 어플리케이션에서 사용되는 기본적인 의존성 범위
컴파일과 런타임에서 모두 사용되고 의존성의 세부 사항은 모듈의 외부에 노출되지 않음
모듈간의 캡슐화를 강화하고 빌드 성능 최적화
compileOnly 컴파일 시에만 사용되는 의존성
어노테이션 처리기, 컴파일러 플러그인 등을 추가할 때 사용
developmentOnly 개발환경에선만 사용하는 의존성
로컬 개발시에만 유용한 도구나 기능들을 포함하고 배포시에는 제외
qnnotationProcessor 컴파일 시 어노테이션을 처리하기 위해 필요한 의존성
런타임에서는 필요하지 않음
testImplementation 테스트 코드에서만 사용하는 의존성
어플리케이션 테스트 컴파일, 테스트 실행 시에만 사용
Junit, Mockito, AssertJ와 같은 데스트 프레임워크나 테스트 도구를 추가할 때 사용
testAnnotationPorcessor 테스트 컴파일 시 어노테이션을 처리하기 위한 의존성을 추가할 때 사용
컴파일러가 테스트 코드의 어노테이션을 처리하는데 필요한 라이브러리를 정의
testRuntimeOnly 테스트를 실행할 때 런타임 시에만 필요한 의존성
테스트 코드를 컴파일 할 때는 필요하지 않고 테스트를 실행할 때만 의존성일 필요할 때 사용
3. 주입의 종류
1) 필드 주입(권장하지 않음)
장점 - 편하다
단점 - 생성자나 setter를 사용해서 주입을 받는것이 아니기 때문에
스프링의 도움 없이는 주입이 불가능하여 테스트에서 사용하기 불편하다
- final 키워드 사용이 불가능하여 불변성을 보장받지 못한다
- 순환참조 시 예외가 발생하지 않는다
@Data
@Component
//스프링 컨테이너가 클래스를 관리하는 Bean으로 등록
public class Coding {
@Autowired
private Computer computer; //필드 주입
public Coding() {
this.computer = computer; //생성자 내에서 computer필드가 이미 주입된 상태(필드 주입에 의존)
}
}
2) 생성자 주입(가장 권장)
생성자에 @Autowired를 사용하면 된다
spring 4.x.x. 이상은 생성자가 한 개 만 있으면 자동으로 @Autowired가 붙는다
만약 private 필드를 초기화 할 때 setter가 없다고 가정하면 생성자를 통해서만 필드를 초기화 해야한다
객체를 ㅎ나 생성할 때는 반드시 생성자가 한 번만 실행되고 이후에는 수정할 수가 없다
그러므로 생성자 주입을 하게 되면 주입된 객체의 불변성이 보장된다
* 생성자 주입을 사용해야 순환참조 문제를 파악하기 쉽고, 단위 테스트도 용이하다
@Data
@Component
//스프링 컨테이너가 클래스를 관리하는 Bean으로 등록
public class Coding {
private Computer computer; //필드 주입
@Autowired //Spring 4.x 에서는 @Autowired 생략 가능
public Coding(Computer computer) {
this.computer = computer; // 생성자 주입을 통해 불변성을 보장
}
}
3) setter 주입
setter를 사용하여 주입하는 방법
setter에 @Autowired를 사용하면 된다
특정 필드의 setter를 사용하지 않아도 해당 클래스 객체를 만들 수 있어서 NullPointException이 발생할 수 있다
setter를 이용하여 언제든지 수정이 가능하게 되므로 불변성이 보장되지 않는다
(객체의 주소가 변경될 가능성이 열려있다는 의미)
@Component
//스프링 컨테이너가 클래스를 관리하는 Bean으로 등록
public class Coding {
@Autowired
@Setter
private Computer computer; //필드 주입
public Coding() {
//기본생성자는 computer 필드를 초기화하지 않는다
//setter를 통해 나중에 주입할 수 있다
}
}
4. 순환참조
A, B클래스가 서로 필드를 주입할 경우 발생하는 문제이다
서로가 주입을 하면서 무한 반복으로 주입을 하게 된다
서로가 주입을 한다는 것 자체가 문제이므로 정상적인 실행이 되어서는 안된다
그러나 필드 주입을 하는 경우 실행 단계에서 오류가 발생하지 않고
나중에 해당 객체를 사용할 때 오류가 발생하여 큰 문제가 발생하게 된다
생성자 주입을 사용했을 경우 서버 실행에서 오류 발생하여 순환참조 문제를 빠르게 파악 가능
------------------------------------------------------------------------------------------------------
day81
테스트 코드(TDD : Test driven development, 테스트 주도 개발)
test 디렉터리에서 작업한다
테스트 코드를 작성하여 실제 코드에 대해 기대되는 바를 명확하게 정의함으로써
불필요한 설계를 피하고 정확한 요구사항에 집중할 수 있다
given : 테스트 실행을 준비하는 단계
when : 테스트를 진행하는 단계
then : 테스트 결과를 검증하는 단계
스프링부트 스타터 테스트 목록
JUnit : 자바 프로그래밍 언어용 단위 테스트 프레임워크
Spring Test & Spring Boot Test : 스프링부트 어플리케이션을 위한 통합테스트 지원
AssertJ : 검증문인 어설션을 작성하는데 사용하는 라이브러리
Hamcrest : 표현식을 이해하기 쉽게 만드는데 사용되는 Matcher 라이브러리
Mockito : 테스트에 사용할 가짜 객체인 목 객체를 쉽게 만들고 관리하고 검증할 수 있게
지원하는 테스트 프레임워크
JSONassert : JSON 용 어설션 라이브러리
JasnPath : JSON 데이터에서 특정 데이터를 선택하고 검색하기 위한 라이브러리
2. 단위 테스트(Unit Test)
작성한 코드가 의도대로 작동하는지 작은 단위를 검증하는 것을 의미(단위는 보통 메소드 단위)
가장 이상적인 테스트 방법은 각 테스트 별로 서로 간섭해서는 안되며,
항상 같은 결과를 기대할 수 있어야 한다
1) JUnit
자바 언어를 위한 단위 테스트 프레임워크
테스트 방식을 구분할 수 있는 어노테이션을 제공한다
@Test 어노테이션으로 메소드를 호출할 때마다 새 인스턴스를 생성하여 독립적인 테스트 가능
예상 결과를 검증하는 어설션 메소드를 제공한다
사용방법이 단순하고 테스트 코드 작성시간이 적다
자동실행, 자체 결과를 확인하고 즉각적인 피드백을 제공한다
2) 테스트 어노테이션
@BeforeAll 전체 테스트를 시작하기 전에 처음으로 한번만 실행
전체 테스트 실행주기에서 한번만 호출되어야 되기 때문에 static선언
@BeforeEach 테스트 케이스를 시작하기 전 매번 실행
각 인스턴스에 대해 메소드를 호출해야 하므로 메소드는 static이 아님
@AfterAll 전체 테스트를 마치고 종료하기 전 한번만 실행
전체 테스트 실행주기에서 한번만 호출되어야 되기 때문에 static선언
@AfterEach 각 테스트 케이스를 종료하기 전에 매번 실행
각 인스턴스에 대해 메소드를 호출해야 하므로 메소드는 static이 아님
결과를 보면 @BeforeAll 어노테이션으로 설정한 메소드가 실행되고 이후
테스트 케이스 갯수 만큼 @BeforeEach -> @ Test -> @AfterEach의 생명주기로 테스트 진행
모든 테스트가 끝나면 @AfterAll 어노테이션으로 설정한 메소드를 실행하고 종료
3) AssertJ
Junit과 함께 사용해 검증문의 가독성을 높여주는 라이브러리이다
Assertions.assertEquals(sum, num1 + num2);
테스트 코드를 위처럼 사용할 수 있지만 기대값과 비교값이 잘 구분되지 않는다
가독성을 위해 AssertJ에서 사용하면 된다
assertThat(num1 + num2).isEqualTo(sum);
메소드이름 설명
isEqualTo(A) A값과 같은지 검증
isNotEqualTo(A) A값과 다른지 검증
contains(A) A값을 포함하는지 검증
doesNotContain(A) A값을 포함하지 않는지 검증
startsWith(A) 접두사가 A인지 검증
endsWith(A) 접미사가 A인지 검증
isEmpty() 비어있는 값인지 검증
isNotEmpty() 비어있지 않는 값인지 검증
isPositive() 양수인지 검증
isNegative() 음수인지 검증
isGreaterThan(1) 1보다 큰 값인지 검증
isLessThan(1) 1보다 작은 값인지 검증
+) 코드작성
@SpringBootTest //테스트용 어플리케이션 컨텍스트 생성
@AutoConfigureMockMvc //MockMVC 생성 및 자동구성
public class ControllerTest {
@Autowired
protected MockMvc mvc;
// 컨트롤러 동작을 가상 HTTP요청을 통해 테스트 할 수 있는 객체
@Autowired
private WebApplicationContext webApplicationContext;
// 웹 어플리케이션의 스프링 컨텍스트를 담고있다,
Spring의 모든 빈을 갖고 있으며 테스트 환경을 구성함
@Autowired
private MemberRepository memberRepository;
// 테스트 중 데이터를 저장하고 조회하는데 사용되는 레포지토리
@BeforeEach //테스트 실행 전 실행하는 메소드
public void mockMvcSetup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
// webApplicationContext를 기반으로 MockMvc 객체를 설정
}
@AfterEach //테스트 실행 후 실행하는 메소드
public void cleanup() {
memberRepository.deleteAll();
// 테스트 중에 추가된 모든 데이터를 삭젠
}
}
@SpringBootTest 메인 어플리케이션 클래스에 추가하는 어노테이션
@SpringBootApplication이 있는 클래스를 찾고
그 클래스에 포함되어 있는 빈을 찾은 후
다음 테스트용 어플리케이션 컨텍스트를 찾는다
@AutoConfigureMockMvc MockMvc를 생성하고 자동으로 구성하는 어노테이션
어플리케이션을 서버에 배포하지 않고도 테스트용 MVC 환경을 만들어
요청 및 전송, 응답 기능을 제공하는 유틸리티 클래스
컨트롤러를 테스트할 때 사용하는 클래스
@BeforeEach 테스트를 실행하기 전에 실행하는 메소드에 적용하는 어노테이션
MockMvcSetUp() 메소드를 실행해 MockMvc를 설정한다
@AfterEach 테스트를 실행한 이후에 실행하는 메소드에 적용하는 어노테이션
cleanUp() 메소드를 실행해 member 테이블에 있는 데이터를 모두 삭제한다
+) 테스트 과정
설정(Setup) 테스트가 시작될 때 필요한 환경을 설정(mockMvc 초기화)
테스트 실행(Execution) MockMvc를 사용해 컨트롤러의 엔드포인트를 호출하고 그 결과를 확인
검증(Verification) 값의 일치 여부 or JSON 응답 등의 내용과 상태코드를 검증하여
테스트의 성공여부 확인
정리(Cleanup) 테스트 후 데이터를 삭제하여 다음 테스트가 영향을 받지 않도록 함
코드 매핑메소드 설명
200 OK isOk() HTTP 응답코드가 200 OK인지 검증
201 Created isCreated() 201 Created인지 검증
302 is3xxRedirection() 302 요청된 리소스가 임시로 다른 url로 이동했음을 검증
400 Bad Request isBadRequest() 400 Bad Request인지 검증
403 Forbidden isForbidden() 403 Forbidden인지 검증
404 Not Found isNotFound() 404 Not Found인지 검증
400번대 응답코드 is4xxClientError() 400번대 응답코드인지 검증
500 Interanl server Error isInternalServerError() 500 Interanl Server Error인지 검증
500번대 응답코드 is5xxServerError() 500번대 은답코드인지 검증
3. Mockito
mock 을 만들고 mock의 행동을 정의하는 stubbing과 작동하는지에 대한
검증을 할 수 있는 verify등 다양항 기능을 제공해주는 프레임워크
1) JUnit에서 Mockito 사용하기
프레임워크이기 대문에 서로 결합하여 사용하기 위해서는 추가 설정이 필요하다
JUnit5에서 @ExtendWith(MockitoExtendion.class)를 사용해야 기능이 확장된다
2) Mock 객체
어떤 객체를 모방하는 가짜 객체이다.
껍데기만 있고 내부 구현부는 존재하지 않는다
Mock 객체를 만드는 것을 Mocking이라고 한다
3) Mockito에서 지원하는 어노테이션
@Mock Mock 객체를 만들어 준다
@InjectMocks Mock 객체를 주입해준다
@Spy Stubbing 하지 않은 메소드는 실제 객체에 정의된 것을 사용하는 객체
관계> UserService는 UserMapper를 주입받는다
사용> UserService를 테스트하기 위해서는 UserMapper가 주입되어야 한다
UserMapper는 개발자가 테스트하고 싶은 대상이 아니기 때문에
UserMapper를 Mock객체로 만들어 UserService에 주입하여 테스트를 진행한다
4) 스터빙(Stubbing)
Mock 객체의 메소드를 실행했을 때의 행위를 미리 정의하는 것
(Mock 객체의 특정 메소드를 실행시키면 특정 값을 반환하거나 예외 발생시키는 등을 설정한다)
5) 스텁(Stub)
스터빙으로 새롭게 정의된 메소드
when(userMapper.select()).thenReturn(userDTO);
//Stubbing을 하는 것
//userMapper.select()는 stub이 되었음
4. Mockito의 스터빙 방법
1) OngoingStubbing 메소드
when()을 먼저 사용하고 OngoingStubbing 메소드를 체이닝 한다
when()이 실행되었을 때 할 행위를 정하는 메소드
when(mock객체.스터빙할 메소드()).OngoingStubbing()
특이사항 : when()의 매개변수로 반환타입이 void인 메소드를 사용할 수 없다
- OngoingStubbing 메소드의 종류
thenReturn() 스텁이 반환할 객체를 정의
thenThrow() 스텁이 throw할 예외를 정의
thenCallRealMethod() 스텁이 아닌 원본 객체의 메소드를 호출
2) Stubber 메소드
stubber 메소드로 시작해서 중간에 when()이 들어간다
when()이후에 스터빙 할 메소드를 체이닝 한다
stubber().when(mock객체).스터빙 할 메소드()
특이사항 : 반환타입이 void 인 메소드를 스터빙 하려면
stubber중 doNothing()을 사용해야 한다
- stubber 메소드의 종류
doReturn() 스텁이 반환할 객체를 정의
doThrow() 스텁이 throw할 예외를 정의
doNothing() 스텁이 아무런 행위도 안하도록 정의(void 메소드도 사용가능)
3) Verify
스텁 메소드를 검증하는 메소드
verify(T mock, VerificationMode mode)
VerificationMode 검증할 값을 정의하는 메소드
주로 times(n)가 많이 사용된다
- VerificationMode의 종류
times(n) n번 호출 되었는지 검증
never 한번도 호출되지 않았는지 검증
atLeastOne 최소 한 번 호출 되었는지 검증
atLeast(n) 최소 n번 호출 되었는지 검증
------------------------------------------------------------------------------------------------------
day82
복습
- MyBatisConfig 클래스
MyBatis와 HikariCP를 설정하는 클래스
@Configuration 설정 클래스 임을 알려주고 스프링에서 자동으로 빈으로 등록
@RequiredArgsConstructor : lombok에서 제공하는 어노테이션으로 생성자를 자동으로
만들어 ApplicationContext를 주입
만든 메소드
hikariConfig
dataSource
sqlSessionFactory
1. Spring MVC
1) Dispatcher 서블릿이 요청을 받으면 Handler Mapping을 통해서 url에 매핑된 컨트롤러를 찾는다
2) Dispatcher 서블릿이 핸들러 어댑터를 실행시킨다
3) 핸들러 어댑터가 올바른 핸들러(컨트롤러)를 실행시키고 핸들러는 결과를 반환한다
4) 핸들러 어댑터가 받은 결과를 ModelAndView 객체로 변환하여 Dispatcher 서블릿에게 전달한다
ModelAndView 객체가 가지고 있는 정보
- Model : 컨트롤러에서 처리한 데이터를 저장(DB에서 가져온 정보 등)
- View : 클라이언트에게 보여줄 페이지의 이름을 저장
5) Dispatcher 서블릿이 받은 결과 중 어떤 View가 필요한지 View Resolver에게 전달한다
6) View Resolver는 올바른 View를 찾아 Dispatcher 서블릿에게 알려준다
7) view는 Dispatcher 서블릿에게 받은 모델 데이터로 html을 완성시켜 클라이언트에게 응답을 보낸다
2. 특징
HttpServletRequest, HttpServletResponse를 거의 사용할 필요없이 구현이 가능하다
다양한 타입의 파라미터와 리턴타입을 사용 가능하다
GET, POST 등의 전송방식에 대한 처리를 어노테이션으로 할 수 있다
3. JSP와 Spring의 데이터 흐름
JSP
DB -> mapper.xml -> DAO -> Controller -> FrontController -> JSP
Spring
DB -> mapper.xml -> Mapper 인터페이스 -> Service -> Controller ->
DispatcherServlet -> View(Thymeleaf, JSP등)
4. 타임리프(Thymeleaf)
서버 사이드 템플릿 엔진으로 스프링부트와 함께 사용하기에 최적화된 템플릿 엔진이다
html 파일에서 데이터바인딩, 조건문, 반복문 등의 기능을 지원
html 파일을 실제 html 구조로 유지할 수 있기 때문에 브라우저에서 바로 확인 가능하다
JSTL 문법과 유사함
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
1) 텍스트 출력
th:text html 요소 안에 데이터를 출력할 때 사용
<p th:text="${msg}>기본텍스트</p>
2) 속성 설정
th:attr thml 요소의 속성값을 동적으로 설정할 때 사용
<a th:attr="href=@{/path/{id}(id=${memberId})}">상세보기</a>
3) URL 표현
th:href, th:src
<img th:src="@{/img/logo.png}" alt="로고">
@{} 표현식 URL 경로 설정할 때 사용, 컨텍스트 경로와 함께 자동으로 처리됨
4) 반복문
th:each 리스트나 배열 데이터를 순회하면서 html 요소 반복적으로 생성
<ul>
<li th:each="member : ${members}" th:text="${member.name}">이름</li>
</ul>
5) 조건문
th:if 조건이 참일 때 해당 요소를 렌더링
th:unless 조건이 거짓일 때 해당 요소를 렌더링
<p th:if="${member.age >= 20}">성인입니다</p>
<p th:unless="${member.age < 20}">미성년자입니다</p>
6) fragment 사용
th:fragment 공통적으로 사용되는 템플릿부분을 정의하고 재사용 할 수 있다
헤더파일
<div th:fragment="header">
헤더내용
</div>
다른파일
<body>
<div th:insert="~{header :: header}"></div>
해당페이지 코드
7) fragment 인클루드
th:insert 다른 html 파일의 fragment를 삽입
th:replace 현재요소를 지정한 fragment로 교체
8) from 처리
th:action 폼의 액션 url 설정
th:object 폼의 데이터 객체 지정
th:field 객체의 필드 바인딩
<form th:acrion--="@{/home}" th:object="${member}">
<input type="text" th:field="*{name}">
*{} th:object로 설정된 객체의 필드 참조
5. REST Controller
RESTful 서비스를 쉽게 만들 수 있도록 스프링에서 제공하는 기술
일반 컨트롤러와 달리 페이지 이동처리를 하지 않으며, url로 요청을 하면 주로 JSON, XML 타입의
데이터를 주고받는다
1) REST(Representational State Transfer)
문서, 이미지, 데이터 등등의 자원을 이름으로 구분하여 데이터를 주고받는 아키텍쳐 스타일을 의미한다
ex) 댓글에 대한 정보가 DB에서 가져와야하는 자원이라면 자운이름을 replies라는 이름으로 정한다
정해놓은 이름을 URL에 표현하여 데이터를 주고 받는다
이 때 무엇을 할 것인지는 HTTP Method를 이용하여 구분한다
GET:/replies/list/{게시글 번호}
DELETE:/replies/{게시글 번호}
2) CRUD 별 HTTP METHOD
CREATE : 삽입(POST)
READ : 조회(GET)
UPDATE : 수정(PUT, PATCH)
-PUT : 전체수정
-PATCH : 부분수정
DELETE : 삭제(DELETE)
=> REST란 자원을 중점으로 직관적인 URL과 HTTP Method를 사용하여 웹 서비스를 제공하는 것을 의미한다
REST라는 규칙을 지켜서 만든 웹 서비스를 RESTful 웹서비스라고 한다
데이터를 주고 받을 때 json을 주로 사용하기 때문에 일반적으로 비동기 통신에서 자주 사용된다
------------------------------------------------------------------------------------------------------
day83
1. 쿼리 순서
from > on > join > where > group by > having > select > order by
2. BoardMapper.xml
페이징 처리 쿼리문
<select id="selectAllPage" parameterType="Criteria" resultType="BoardListDTO">
// 잘못 인식하지 않도록 CDATA 사용, <>를 쿼리문의 태그로 인식하지 않도록 사용
// <> 안에 문자들이 XML 파서에 의해 잘못 인식될 수 있음
<![CDATA[
// 최종적으로 알고싶은 정보 (컬럼들 반환)
SELECT BOARD_ID, TITLE, LOGIN_ID, FILE_ID, NAME, UPLOAD_PATH, UUID
FROM (
// rownum을 사용한 페이징처리
// rownum은 오라클에서 각 행에 임시로 부여되는 고유 번호(각 행에 번호 부여)
SELECT ROWNUM AS RNUM, BOARD_ID, TITLE, LOGIN_ID, FILE_ID, NAME, UPLOAD_PATH, UUID
// 내부 select 시작부분
// 게시물, 사용자 테이블을 join해서 게시물 작성자의 login_id를 알아내기 위함
FROM (
SELECT B.BOARD_ID, TITLE, U.LOGIN_ID,
F.FILE_ID, F.NAME, F.UPLOAD_PATH, F.UUID
FROM TBL_BOARD B JOIN TBL_USER U
ON B.USER_ID = U.USER_ID // 여기까지
// 왼쪽 테이블 기준으로 오른쪽 테이블이 맞춰지도록 LEFT JOIN
// 각 게시물에 첨부된 파일 정보를 가져옴
// 첨부파일이 여러개일 때 rank() 함수를 사용해 각 게시물마다 가장 첫번째 파일만 선택
LEFT JOIN (
SELECT FILE_ID, NAME, UPLOAD_PATH, UUID, BOARD_ID
FROM (
SELECT FILE_ID, NAME, UPLOAD_PATH, UUID, BOARD_ID,
RANK() OVER(PARTITION BY BOARD_ID ORDER BY FILE_ID) RK
FROM TBL_FILE
)
// 첫번째 파일만 선택하겠다는 조건 where
WHERE RK = 1
) F
ON B.BOARD_ID = F.BOARD_ID
// board_id로 내림차순 정렬(최신순)
ORDER BY BOARD_ID DESC
)
// 페이지당 항목 수 제한
// rownum이 #{page} * #{amount}이하인 항목만 선택
WHERE ROWNUM <= #{page} * #{amount}
)
// 최종페이징 처리
// rnum이 (#{page} -1) * #{amount} 보다 큰 항목만 선택
WHERE RNUM > (#{page} - 1) * #{amount}
]]>
</select>
3. REST Controller
RESTful 서비스를 쉽게 만들도록 스프링에서 제공하는 기술
일반 컨트롤러와 다리 페이지 이동처리 하지 않음
url 로 요청시 주로 json, xml 타입의 데이터를 주고받음
요청매핑(request mapping)
http 메소드에 따라 클라이언트 요청을 특정 메소드에 매핑
지원처리(resource handling)
클라이언트가 요청한 자원에 대해 crud 작업 수행
응답생성(response generation)
요청 처리 후 , 클라이언트에게 json, xml 형식으로 응답 반환
REST(Representational State Transfer)
문서, 이미지, 데이터 등 자원을 이름으로 구분해 데이터를 주고받는 아키텍처 스타일을 의미
ex) 댓글에 대한 정보가 db에서 가져와야 하는 자원
-> 자원이름 replies로 정하기
-> 정해놓은 이름을 url에 표현하여 데이터 주고받기
-> 무엇을 할 것인지는 http method를 이용하여 주고받기
get:/replies/list/{게시글번호}
delete:/replies/{게시글번호}
CRUD 별 HTTP 메소드
create 삽입(post)
read 조회(get)
update 수정(put, patch), 전체 put / 부분 patch
delete 삭제(delete)
FileApi
// 파일 저장 경로를 주입받기 위해 사용하는 어노테이션
// 괄호안에 경로를 해당 경로로 지정
// fileDir 변수에 저장
@Value("C:/upload/")
private String fileDir;
// 특정 게시글에 대한 파일 목록을 조회하는 엔드포인트 (endpoint : 클라이언트가 서버의 자원에
접근하기 위해 요청을 보내는 특정 URL을 의미)
// HTTP GET 요청을 처리하는 매핑 어노테이션, 주어진 URL 패턴에 맞는 요청을 처리
@GetMapping("/v1/boards/{boardId}/files")
// URL 경로에서 {boarId} 부분을 추출하여 boardId 변수에 매핑
public List<FileDTO> fileList(@PathVariable("boardId") Long boardId) {
return fileService.findList(boardId);
}
'Spring Boot' 카테고리의 다른 글
국비지원) Spring Boot 프로젝트 28일차 (1) | 2024.10.24 |
---|---|
국비지원) Spring Boot 프로젝트 27일(241024) (3) | 2024.10.24 |
국비지원) Spring Boot 프로젝트 20,21일차 (1) | 2024.10.17 |
국비지원) Spring Boot 프로젝트 19일차 (1) | 2024.10.16 |
국비지원) Spring Boot 프로젝트 18일차 (0) | 2024.10.14 |