티스토리 뷰

728x90
반응형

1. API 구현

(1) 검색

// queryDSL 설정
    implementation "com.querydsl:querydsl-jpa"
    implementation "com.querydsl:querydsl-core"
    implementation "com.querydsl:querydsl-collections"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" // querydsl JPAAnnotationProcessor 사용 지정
    annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 대응 코드
    annotationProcessor "jakarta.persistence:jakarta.persistence-api" // java.lang.NoClassDefFoundError (javax.annotation.Entity) 대응 코드
  • build project 랑 execute gradle 명령어의 충돌을 방지하고 같은 동작을 하기 위해 아래 코드도 build.gradle에 추가한다.
// Querydsl 설정부
def generated = 'src/main/generated'

// querydsl QClass 파일 생성 위치를 지정
tasks.withType(JavaCompile) {
    options.getGeneratedSourceOutputDirectory().set(file(generated))
}

// java source set 에 querydsl QClass 위치 추가
sourceSets {
    main.java.srcDirs += [ generated ]
}

// gradle clean 시에 QClass 디렉토리 삭제
clean {
    delete file(generated)
}
  • 두 개의 repository 안에 아래의 코드를 추가한다.
// Article
JpaRepository<Article, Long>,
QuerydslPredicateExecutor<Article>

// ArticleComment
JpaRepository<ArticleComment, Long>,
QuerydslPredicateExecutor<ArticleComment>
  • 부분 검색은 추가적으로 구현해야 한다.
    • QuerydslBinderCustomizer<QArticle>{} 사용 Article comments에도 유사하게 작성해준다.
QuerydslBinderCustomizer<QArticle> {
    @Override
    default void customize(QuerydslBindings bindings, QArticle root) {
        bindings.excludeUnlistedProperties(true);
        bindings.including(root.title, root.content, root.hashtags, root.createdAt, root.createdBy);
        bindings.bind(root.title).first(StringExpression::containsIgnoreCase);
        bindings.bind(root.content).first(StringExpression::containsIgnoreCase);
        bindings.bind(root.hashtags).first(StringExpression::containsIgnoreCase);
        bindings.bind(root.createdAt).first(DateTimeExpression::eq);
        bindings.bind(root.createdBy).first(StringExpression::containsIgnoreCase);
    }
  • 위에 지정된 것은 부분 검색 기능이 작동되는 것을 확인할 수 있다.
  • Querydsl 기능은 gitignore 에 포함시켜야 한다. 자동 생성되는 것이며 변경이 있을 때마다 반영되어 생성되기 때문에 제외하는 것이 좋다.
  • .gitignore 파일에 /src/main/generated 주소를 포함시켜주면 된다.

 

2. 게시판 서비스 View 만들기

(1) 뷰 엔드포인트 테스트 정의

  • 의존성 추가
    • Thymeleaf (spring initializr 참고) 코드 추가
  • controller > ArticleController 생성
  • 모든 뷰의 시작 주소가 /articles/ 이기 때문에 @RequestMapping("/articles")를 해주면 이후로 생략 가능하기 때문에 편하다.
  • 테스트 생성
    • WebMvcTest
      • @Autowired 를 꼭 명시해줘야 한다.
@DisplayName("게시글 리스트 페이지 - 정상 호출")
@Test
void givenSearchKeyword_whenSearchingArticlesView_thenReturnsArticlesView() throws Exception {
        mvc.perform(get("/articles"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.TEXT_HTML))
                .andExpect(model().attributeExists("articles"));
    }
@DisplayName("게시글 검색 전용 페이지 - 정상 호출")
@Test
void givenNothing_whenRequestingArticleSearchView_thenReturnsArticleSearchView() throws Exception {
    mvc.perform(get("/articles/search"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.TEXT_HTML));
}
@DisplayName("게시글 해시태그 검색 페이지 - 정상 호출")
@Test
void givenNothing_whenRequestingArticleSearchHashtagView_thenReturnsArticleSearchHashtagView() throws Exception {

    mvc.perform(get("/articles/search-hashtag"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.TEXT_HTML));
}
  • WebMvcTest는 모든 컨트롤러를 다 불러들인다.
    • 테스트 대상만 읽어 들이려면 WebMvcTest(해당 컨트롤러 이름.class)를 사용한다.
  • 실패하는 테스트를 모두 disable을 시켜 commit을 남기는 방법도 있다.
    • @Disabled("왜 제외하는지 이유 입력 ex 구현중")
  • 뷰의 이름에 대한 검사도 할 수 있다.
    • .andExpect(model().attributeExists("articles/search")

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

https://bit.ly/43z0P6S

 

 

#패스트캠퍼스 #포트폴리오 #직장인자기계발 #환급챌린지 #포트폴리오챌린지 #패스트캠퍼스후기 #초격차패키지 #오공완

728x90
반응형
댓글