1. build.gradle 설정
dependencies {
...
// Junit5
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform {
includeTags 'fast'
excludeTags 'slow'
}
}
build.gradle의 dependencies와 test에 위의 코드를 추가한다.
2. application.yml 설정
원하는 DB를 연결하면 된다. 나는 MySQL과 MongoDB를 함께 사용하였다.
3. Test Package 만들기
src/test/java 밑에 테스트 패키지를 생성해준다.
4. Test Class 생성
JUnit5에서는 JUnit4의 @RunWith의 어노테이션 대신에 다음의 어노테이션을 달아주어야 한다.
- @ExtendWith(SpringExtension.class)
그 외에도 @DisplayName(str): 클래스를 설명할 수 있음 등 다양한 어노테이션이 있지만, 지금 이 프로젝트에서 반드시 알아야 할 세가지 어노테이션이 있다.
- @DataJpaTest: JPA 테스트시 사용
- @DataMongoTest: MongoDB 테스트시 사용
jpa 말고도 mvc 테스트를 할 수도 있고, mongoDB 대신 redis 등 다른 DB도 테스트할 수 있는데 모두 필요한 어노테이션이 다르다. 자세한 것은 스프링 공식 홈페이지를 확인하면 된다.
- @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE): 테스트 시 사용할 데이터베이스 (@DataJpaTest + 테스트 용으로 외부 DB 사용시)
@DataJpaTest는 기본적으로 내장된 메모리 DB를 이용해 테스트를 실행하는데, 물리적인 MySQL DB로 테스트를 시도하면 문제가 발생한다. 그렇기 때문에 테스트 실행시 사용할 DB를 지정해야 하는데 그게 @AutoConfigureTestDatabase 어노테이션이다.
replace로 any, auto_configured, none 세 가지의 ENUM이 있는데,
- any: 자동 구성, 수동 구성 상관 없이 DataSource 빈을 내장된 DB(H2, DERBY, HSQLDB)로 교체
- auto_configured: 자동 구성된 경우에만 DataSource 빈 교체
- none: DataSource 빈을 교체하지 않음
더 자세한 내용은 아래 블로그를 참고하면 된다. (MongoDB만 사용하면 필요 없음)
4-1. MySQL (MemberRepositoryTest)
Member.class
@Setter
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "member", uniqueConstraints = {
@UniqueConstraint(columnNames = "email")
})
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonIgnore
private Long id;
@NotNull
@Column(nullable = false)
private String name;
@Email
@Column(nullable = false)
private String email;
}
MemberRepository.interface
@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByEmail(String email);
Optional<Member> findByName(String name);
}
MemberRepositoryTest.class
@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@DisplayName("Member Repository test case")
public class MemberRepositoryTest {
@Autowired
private MemberRepository memberRepository;
@Test
void findMemberByEmailTest(){
memberRepository.save(Member.builder()
.email("test@gmail.com")
.name("test").build());
Member member = memberRepository.findByEmail("test@gmail.com")
.orElseThrow(()-> new BadRequestException("해당하는 사용자가 없습니다."));
assertEquals("test", member.getName());
}
}
위의 파일을 실행하면 정상적으로 테스트가 돌아간다.
4-2. MongoDB (BoardRepositoryTest)
Board.class
@Builder
@Getter
@Setter
@Document
public class Board {
@Id
private String id;
private String writer;
private String content;
private String image_url;
private String created_at;
}
BoardRepository.interface
@Repository
public interface BoardRepository extends MongoRepository<Board, String> {
// "db.orders.find().sort({"created_date": -1"}).skip((page-1)*20).limit(20)"
@Aggregation(pipeline = {
"{'$sort': {'created_at': -1}}", /* create_at 기준 -1(내림차순) 정렬 */
"{'$skip': ?0}", /* 0번째 파라미터(start) 값만큼 skip */
"{'$limit': 20}" /* 최대 20개 가져옴 */
})
List<Board> findN(int start);
}
위의 @Aggregation 어노테이션은 JPA의 @Query 어노테이션과 비슷한 역할을 한다.
해당 함수는 최근 순으로 정렬한 게시글을 page 부터 20개씩 끊어 가져오는 함수이다.
BoardRepositoryTest.class
@ExtendWith(SpringExtension.class)
@DataMongoTest
@DisplayName("Board Repository test case")
public class BoardRepositoryTest {
@Autowired
private BoardRepository boardRepository;
@Test
void getCardsTest(){
int n = 10;
for(int i=0; i<n; i++){
boardRepository.save(Board.builder()
.writer("테스트" + (i + 1))
.content("테스트 컨텐트" + (i + 1))
.created_at("2022.02.22")
.build());
}
List<Board> boardList = boardRepository.findAll();
assertEquals(n, boardList.size());
}
@Test
void getNCardsTest(){
int n = 30;
for(int i=0; i<n; i++){
boardRepository.save(Board.builder()
.writer("테스트" + (i + 1))
.content("테스트 컨텐트" + (i + 1))
.created_at("2022.02.22")
.build());
}
int page = 2;
List<Board> boardList = boardRepository.findN(page);
assertEquals(20, boardList.size());
for(int i=1; i<n; i++){
assertNotEquals(boardList.get(i-1).getId(), boardList.get(i).getId());
}
}
}
결과는 다음과 같이 나온다.
만약 assertion이 잘못되었다면 다음과 같이 내가 설정한 기댓값과 실제 결과값, 그리고 어디의 assertion에서 에러가 났는지도 알려준다.