1.https://spring.io/tools접속하여 STS(for Eclipse) 설치 후 실행 2. 상단 Quick Access에 Git Repositories 검색 후 클릭 3. Git Repositories 탭으로 가서 Clone a Git repository 4. gitlab 사이트 Import 하려는 프로젝트로 들어가서 Clone -> Clone with HTTPS 부분 복사 5. STS로 돌아가서 URL 부분에 붙여넣기 하면 세부 항목까지 자동 입력(Port는 빈칸) 6. master 브랜치 체크 후 Next & Finish 7. Git Repositories 탭의 프로젝트 우클릭 후 Import Projects 8. Package Explorer에 받아진 프로젝트 확인 9. Window > Preferences > Server > Runtime Environments > 우측 Add > Tomcat 버전 선택 > Browse... 클릭 후 다운로드한 Tomcat 폴더 선택 > Finish > Apply and Close
(Tomcat 다운로드https://tomcat.apache.org) 10. 상단 Quick Access에 Servers 검색 후 클릭 11. Servers 탭에서 우클릭 > New > Server > Tomcat 버전 선택 > Available 부분에 있는 항목 선택 후 Add > Finish 12. Project는 우클릭 후 Maven > Update Project...와 최상단 탭 Project > Clean...
13. x 표시가 사라지지 않는다면 설치되지 않은 플러그인이 있는지 확인
- Lombok을 사용하는 경우 -
Eclipse의 경우 Maven / Gradle에 Lombok Dependency가 추가되어 있어도 Lombok을 따로 설치해 줘야 한다.
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
}
2. private final (생성자 주입 : Constructor Injection)
@Service
public class ArticleService {
private final ArticleRepository articleRepository;
public ArticleService(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}
}
private final 방식이 더 좋은 이유
1. 순환 참조를 방지할 수 있다. (순환 참조 발생 시, Application이 구동되지 않는다.)
Article 서비스에서 테스트를 원하는 메소드명 우클릭 Generate > Test를 클릭하고
열린 창 하단에 테스트를 할 메소드명을 체크 후 OK를 클릭한다.
ArticleServiceTest라는 클래스 파일이 만들어지고
이 파일의 경로는 src > test > java > com.example.firstproject > service가 된다.
H2 DB를 사용하고 있었기 때문에 data.sql을 참고해 테스트 코드를 작성한다.
예상 시나리오 작성 -> 실제 결과와 비교하여 검증
<data.sql>
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (2, 'AAAA', '1111');
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (3, 'BBBB', '2222');
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (4, 'CCCC', '3333');
<ArticleServiceTest>
package com.example.firstproject.service;
import com.example.firstproject.dto.ArticleDto;
import com.example.firstproject.entity.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest // 해당 클래스는 스프링부트와 연동되어 테스팅된다.
class ArticleServiceTest {
@Autowired ArticleService articleService;
@Test
void readAll() {
// 예상
Article a = new Article(2L, "AAAA", "1111");
Article b = new Article(3L, "BBBB", "2222");
Article c = new Article(4L, "CCCC", "3333");
List<Article> expectedList = new ArrayList<Article>(Arrays.asList(a, b, c));
// 실제
List<Article> articleList = articleService.readAll();
// 비교
assertEquals(expectedList.toString(), articleList.toString());
}
@Test
void read_success() { // read 메소드 성공 테스트
// 예상
Long id = 2L;
Article expected = new Article(id, "AAAA", "1111");
// 실제
Article article = articleService.read(id);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
void read_fail() { // read 메소드 실패 테스트 // 존재하지 않는 id를 입력한 경우
// 예상
Long id = -1L;
Article expected = null;
// 실제
Article article = articleService.read(id); // return articleRepository.findById(id).orElse(null); 이렇게 작성되어 있으므로 null 값을 갖는 expected로 비교
// 비교
assertEquals(expected, article); // null은 toString 메소드를 호출할 수 없음
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void create_success() { // create 메소드 성공 테스트 // title과 content만 있는 dto 입력
// 예상
String title = "DDDD";
String content = "4444";
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = new Article(1L, title, content);
// 실제
Article article = articleService.create(dto);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void create_fail() { // create 메소드 실패 테스트 // id가 포함된 dto 입력
// 예상
String title = "DDDD";
String content = "4444";
ArticleDto dto = new ArticleDto(2L, title, content);
Article expected = null;
// 실제
Article article = articleService.create(dto); // id가 존재하는 경우 null return하도록 작성되어 있음
// 비교
assertEquals(expected, article);
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_success_1() { // update 메소드 성공 테스트 케이스 1 // 존재하는 id와 변경할 title, content만 있는 dto 입력
// 예상
Long id = 2L; // 대상 id
String title = "AAAAAAAA"; // 변경할 title
String content = "11111111"; // 변경할 content
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = new Article(id, "AAAAAAAA", "11111111");
// 실제
Article article = articleService.update(id, dto);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_success_2() { // update 메소드 성공 테스트 케이스 2 작성해보기
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_fail_1() { // update 메소드 실패 테스트 케이스 1 // 존재하지 않는 id와 변경할 title, content만 있는 dto 입력
// 예상
Long id = -1L; // 대상 id
String title = "AAAAAAAA"; // 변경할 title
String content = "11111111"; // 변경할 content
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = null;
// 실제
Article article = articleService.update(id, dto); // id에 해당하는 엔티티가 없는 경우 null return하도록 작성되어 있음
// 비교
assertEquals(expected, article);
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_fail_2() { // update 메소드 실패 테스트 케이스 2 작성해보기
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void delete_success_1() { // delete 메소드 성공 테스트 케이스 1 // 존재하는 id 입력
// 예상
Long id = 2L;
Article expected = new Article(id, "AAAA", "1111");
// 실제
Article article = articleService.delete(id);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void delete_fail_1() { // delete 메소드 실패 테스트 케이스 1 // 존재하지 않는 id 입력
// 예상
Long id = -1L;
Article expected = null;
// 실제
Article article = articleService.delete(id);
// 비교
assertEquals(expected, article);
}
}
테스트 코드 작성 후 메소드 옆 재생 버튼 클릭 > Run ArticleServiceTest 클릭하면 해당 메소드의 테스트가 시작된다.
화면 좌측 하단 Show Passed, Show Ignored를 선택하고
메소드명 옆에 녹색 체크(테스트 정상) 또는 X 표시(테스트 실패)를 확인한다.
모든 메소드에 대해 테스트를 진행하고자 한다면 클래스명 옆에 있는 재생 버튼을 클릭하면 된다.
조회가 아닌 생성, 변경, 삭제 테스트의 경우
Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다. (어노테이션 추가 @Transactional)
# H2 DB, 웹 콘솔 접근 허용
spring.h2.console.enabled=true
# 실행과 동시에 데이터 생성 가능하도록 변경
spring.jpa.defer-datasource-initialization=true
# JPA 로깅 설정
# 디버그 레벨로 쿼리 출력
logging.level.org.hibernate.SQL=DEBUG
# 정리해서 보여주기
spring.jpa.properties.hibernate.format_sql=true
# 파라미터 보여주기
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
# DB URL 고정 설정
# 유니크 URL 생성 X
spring.datasource.generate-unique-name=false
# 고정 URL 설정
spring.datasource.url=jdbc:h2:mem:testdb
<build.gradle에 추가=""> (Lombok 추가 : 코드 간소화, 로깅 가능하게 해주는 라이브러리)</build.gradle에>