- 프로젝트 아이디어 선정!
- @DataJpaTest
사실 크게 하고 싶은 프로젝트는 없었는데, "실제 서비스할 것을 염두에 두고 프로젝트를 시작하면 좋다"라는 말을 들었다. 생각해보니 저 취업하려고 포폴에 넣으려고 플젝 시작했어요ㅋ 보다는 실생활에서 이러이러한걸 느꼈고, 이러이러한걸 해결해보고 싶어서 이러이러한 프로젝트를 시작해 보았습니다. 라는게 더 먹힐 것 같긴 했다.
사용자는 공유하고자 하는 요리 레시피의 각 단계와 그에 맞는 설명과 사진을 추가할 수 있습니다.
소요 시간, 필요 재료, 음식 종류 등의 기본 정보가 필요합니다.
각 레시피 단계 단위로 댓글을 달 수 있습니다. (이용자들의 추가 팁, 제품 추천 등)
좋아요, 북마크, 후기 기능이 있습니다. 후기에 별점과 키워드를 추가할 수 있습니다. (ex.간단한/자극적인/건강한/유용한)
레시피 작성자와 후기 작성자의 별점, 키워드, 요리 종류, 소요 시간 등을 기준으로 레시피를 검색하는 것이 가능합니다.
레시피 작성자가 지정한 재료를 쿠팡 같은 커머스 사이트와 연결하는 것도 좋은 아이디어인듯?
농가로 등록된 생산자가 생산 예상 수량과 가격, 마감 날짜 및 시간을 정해두고 폼을 오픈하면, 소비자가 최소 요구 금액/수량 이상의 상품을 공구 형식으로 구매합니다.
농가는 정기 공구 폼을 오픈할 수 있고, 소비자 역시 이를 구독할 수 있습니다.
마감 시간이 얼마 남지 않았을 때 혹은 공구 수량이 많이 남지 않았을 때 타임 딜 세일 같은 기능을 도입할 수도 있습니다.
사용자가 지정한 특정 키워드가 포함되어 있으며 + 설정한 가격 이하의 공구가 떴을 때 알람을 보낼 수도?
농가 소개, 공구 항목 소개, 그리고 후기 기능이 존재합니다.
수능이나 모의고사 기출이 기본적으로 업로드 되어있고, 학원 같은 교육기관, 출판사, 혹은 이용자인 학생 본인들이 제작한 문제를 업로드할 수 있습니다.
문제별로 질문 게시판이 존재합니다. BOJ의 질문 게시판과 유사합니다.
문제별로 해답 게시판도 존재하는데, 학생들이 원하는 경우 자신의 해결법을 공유할 수 있습니다. (정답을 맞춰야 해답 게시판 열람 가능)
과목별, 과목 안에서는 단원별(혹은 개념별) 분류가 존재합니다. (BOJ 알고리즘 분류)
출판사나 학원 입장에선 자신이 제작한 문제를 업로드하고 학생들이 해당 문제를 다운받은 수만큼 수익을 올릴 수 있습니다.
학생들은 네이버 웹툰의 [쿠키] 같은 개념으로 문제 다운로드권을 구매해서 출판사, 혹은 학원들이 업로드한 문제를 사이트 내 재화로 구매할 수 있습니다.
1번은 메모장에 1번 2번 해서 하나하나 글자로 저장하는 내 귀찮음 때문에, 2번은 우리 가문(?)의 생업에 영감을 받아, 3번은 사교육 격차 해소(ㅋㅋ)를 동기로 떠올려본 주제이다. 뭐가 적절할지, 각 프로젝트에 어떤 기능을 붙일 수 있고 그를 위해 공부해야하는 것이 무엇인지는 멘토님과 얘기하다보면 나오겠지..
들어가기 전에, Spring에서 인터페이스에 @Component
, @Repository
등의 빈 등록용 어노테이션을 붙일 필요가 없다는 얘기를 들었다. 더불어 JpaRepository<T,ID>
를 extends한 레포지토리 인터페이스 역시 @Repository
를 붙일 필요가 없다는 얘기를 들어버렸다.
이것은 마치..
@RequestBody
로 사용자 요청을 받는 DTO에 @Setter
을 쓸 필요가 없다는 얘기를 들었을 때와 같은 충격.. (인터페이스는 인스턴스 생성이 안되니 구현체가 없으면 @Component
가 있어도 실제 빈으로 등록되지 못하는게 아닐까~ 생각하긴 함.)
Spring에서 인터페이스와 그 구현이 있다면
@Component
(또는@Service
,@Repository
등과 같은 다른 특수 어노테이션)로 구현 클래스에만 어노테이션을 달면 충분합니다. 인터페이스 자체에는 특정 어노테이션이 필요하지 않습니다. 또한, Spring Data JPA에서JpaRepository
를 확장하는 인터페이스에는@Repository
어노테이션이 필요하지 않습니다.@Repository
는 클래스가 저장소의 역할을 수행하고 예외를 반환할 수 있음을 나타내는 데 사용되는 마커 주석입니다.
그래서 일단 이전에 했던 프로젝트 domain 패키지의 Repository 인터페이스를 확인해보니 어노테이션을 안달아놨다. 아마 깜빡했던 것 같은데..
// 휑~
public interface UrlRepository {
List<ShortenUrl> findAll();
Optional<ShortenUrl> findByShortenUrl(String shortenUrl);
ShortenUrl save(ShortenUrl shortenUrl);
}
아무튼, 그렇더라도.. 일반적으로 리포지토리 인터페이스에 @Repository
를 추가하여 역할을 명시적으로 전달하고 해당 어노테이션이 제공하는 스프링 repository 특정 예외 제공 등의 기능을 이용하기 위해
@DataJpaTest
는 JPA Repository 테스트를 위해 JPA 관련한 테스트 자동설정을 해주는 어노테이션이다. 기본적으로 포함된 H2 데이터베이스를 사용하지만, 필요한 경우 다른 DB로 구성할 수 있고, @Entity
클래스를 스캔하여 테스트 중 엔티티 클래스를 사용할 수 있도록 하고, @Test
메소드 단위로 트랜잭션-롤백을 수행하고, 테스트 과정 중 수행되는 sql문을 출력해주고..헥헥..
어노테이션 설명을 보자!
Annotation for a JPA test that focuses only on JPA components.
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to JPA tests.
(같은 얘기다)
본격적으로 Repository 테스트를 작성하기 전, @ActiveProfiles
를 통해 테스트 환경에서 사용할 spring profile을 지정해야 한다.
현재 프로젝트에서 url 엔티티를 저장할 구현체로 3개를 두고 있는데, 난 아래의 JPA를 통해 구현된 Repository를 테스트 할 것이다.
@Repository
@Profile("jpa")
public interface UrlJpaRepository extends JpaRepository<ShortenUrl, String> {
Optional<ShortenUrl> findByShortenUrl(String shortenUrl);
}
사용하는 profile은 "jpa"이다. 테스트 클래스에 그대로 적용시켜준다. 사용할 JpaRepository 클래스도 @Autowired
해주었다.
@DataJpaTest
@ActiveProfiles(profiles = "jpa")
public class UrlRepositoryTest {
@Autowired
private UrlJpaRepository urlJpaRepository;
}
그리고 이제 시작! 테스트할 로직은, 1) 엔티티 객체가 세이브되었는지 확인, 2) 세이브 된 객체의 초기값이 잘 설정되었는지 확인 이다.
@DisplayName("저장된 ShortenUrl 검색 테스트")
@Test
public void saveTest() {
String original = "https://test.com";
String shorten = ShortenUrl.generateShortenUrl();
urlJpaRepository.save(ShortenUrl.builder()
.originalUrl(original)
.shortenUrl(shorten)
.build());
Assertions.assertNotNull(urlJpaRepository.findByShortenUrl(shorten));
}
@DisplayName("shortenUrl 초기값 세팅 테스트")
@Test
public void myTest() {
String original = "https://test.com";
String shorten = ShortenUrl.generateShortenUrl();
urlJpaRepository.save(ShortenUrl.builder()
.originalUrl(original)
.shortenUrl(shorten)
.build());
ShortenUrl found = urlJpaRepository.findByShortenUrl(shorten).orElseThrow();
Assertions.assertEquals(original,found.getOriginalUrl());
Assertions.assertEquals(shorten,found.getShortenUrl());
Assertions.assertEquals(0,found.getRequestedNumber());
}
근데 이 테스트코드는 내가 짠 로직에 대한 검증이라기보단 JPA 동작 자체를 검증하는 테스트인데.. @DataJpaTest
자체가 테스트로써 유의미하게 작용이 될까? 일단 안하는 것 보다는 낫다는 생각이지만..