자바를 이용해 애플리케이션을 만들었다면 동작을 검증하기 위한 다양한 테스트를 작성하기 위해선 대표적으로 JUnit을 활용할 수 있다.
JUnit 5
The JUnit team uses GitHub for version control, project management, and CI.
junit.org
가장 최근 버전인 JUnit 5와 JUnit 4은 약간의 차이가 있어서 공식 문서를 참고하면 좋고, 기본적으로 JUnit을 이용해 테스트를 하기 위해선, 내가 테스트하고자 하는 입출력을 정의해주어야 한다. 하지만 사람이 직접 생각할 수 있는 케이스는 한정적이고 매번 다르다. 오늘 생각하지 못 했던 케이스가 내일은 생각날 수도 있다.
유저 생성 시 이메일 검증 테스트
RFC 5322에 따르면 이메일은 특정 형식을 가지고 있는 것이 공통적으로 약속된 규정이다.
RFC 5322: Internet Message Format
This document specifies the Internet Message Format (IMF), a syntax for text messages that are sent between computer users, within the framework of "electronic mail" messages. This specification is a revision of Request For Comments (RFC) 2822, which itsel
datatracker.ietf.org
자바와 스프링, JPA를 사용한 애플리케이션에서 사용자 도메인의 구성 중 하나인 이메일 값 객체를 예시로 만들어보았다.
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Email {
private static final Pattern EMAIL_PATTERN = Pattern.compile(
"^[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+[.][0-9A-Za-z]+$");
private String address;
public Email(String address) {
validate(address);
this.address = address;
}
private void validate(String email) {
if (StringUtils.isBlank(email)) {
throw new InvalidParameterException(UserErrorCode.BLANK_EMAIL);
}
boolean matches = EMAIL_PATTERN.matcher(email)
.matches();
if (!matches) {
throw new InvalidParameterException(UserErrorCode.INVALID_EMAIL_FORMAT);
}
}
}
이메일을 생성할 때 생성자에서 검증 로직인 validate()를 호출하며 이메일의 유효성을 판단한다.
그 다음, 이메일을 사용하는 사용자를 생성하는 테스트를 JUnit을 사용해서 작성해보았다. 사용자 객체는 신경쓰지말고, 이메일 부분만 집중해보자.
@Test
void User_인스턴스를_생성한다() {
// given
String email = "email@example.com";
String password = "password123!";
String nickname = "nickname";
// when
User user = User.builder()
.passwordEncoder(new BCryptPasswordEncoder())
.email(email)
.password(validPassword)
.nickname(validNickname)
.build();
// then
assertThat(user).extracting("email", "nickname")
.containsExactly(email, nickname);
}
이렇게 작성한 테스트는 문제없이 통과할 것이고, 테스트 커버리지에 이메일 클래스와 메서드들이 포함될 것이다.
하지만, 이메일 형식은 사실 여러가지가 존재한다.
- user-email@company.com
- user.email@gmail.com
- useremail@domain.co.kr
- useremail@domain.hk
이를 작성하기 위해서 중간에 @가 들어간 무수히 많은 케이스를 전부 확인해야할까? 전부 ㅇ넣는 것이 의미있고 서비스의 품질을 향상시키긴 할 것이다. 하지만 동시에 너무 많은 리소스를 잡아먹는 것이 아닐까? 그렇다면, 이메일의 형식을 유지하면서 무작위 값을 모방해 테스트를 진행한다면, 생각하지 못했던 케이스를 무작위로 테스트할 수 있지 않을까? 테스트에 사용할 입력을 난수로 정하는 것이다.
DataFaker
역시 의문을 가지고 찾아보면 항상 무언가가 이미 존재한다. 자바의 경우엔, Java Faker가 존재한다.
GitHub - DiUS/java-faker: Brings the popular ruby faker gem to Java
Brings the popular ruby faker gem to Java. Contribute to DiUS/java-faker development by creating an account on GitHub.
github.com
다양한 사물은 물론이고 Lorem, 이름, 직업, 인터넷 도메인, 성별, 경제, 색깔, 시간 등의 기본적인 입력이나 셰익스피어, 반지의 제왕, 스타트렉 등의 문학 관련이나 오버워치, 리그오브레전드, 스타크래프트 등의 게임 관련 데이터도 랜덤하게 생성할 수 있다. 이러한 다양한 랜덤 데이터를 심지어 영어 뿐만이 아니라 다양한 언어를 지원한다.
하지만 Java Faker 라이브러리의 마지막 업데이트가 3년전이다. 더 자세히 찾아보면, Java Faker는 더 이상 유지되지 않고 Data Faker를 추천해준다.
Random Data Generator for Java and Kotlin - Datafaker
Generating fake data has never been easier Create fake data for your JVM programs within minutes, using our wide range of more than 200 data providers. Get started in minutes. Quick start
www.datafaker.net
Data Faker는 문서도 더욱 잘되어있고 예시 등도 많다. 더 자세히 알고싶다면 공식 문서를 쓱 훑어보는 것을 추천한다. 무한대 등 직접 구현이 필요한 값도 제공해준다!
이제 Data Faker를 사용해 테스트가 진행될 때마다 랜덤 데이터로 테스트를 하도록 작성해보겠다.
우선 build.gradle에 data faker 의존성을 추가해준다.
implementation 'net.datafaker:datafaker:2.0.2'
이제 하드코딩된 문자열이 아니라 의미를 담은 무작위 값은 다음과 같이 생성할 수 있다.
// 랜덤 데이터 생성기
Faker faker = new Faker();
// 랜덤 이메일
String email = faker.internet()
.emailAddress();
// 랜덤 비밀번호
String password = faker.internet()
.password();
String passwordIncludingDigits = faker.internet()
.password(true);
String passwordRange = faker.internet()
.password(8, 16);
String passwordUpperCase = faker.internet()
.password(8, 16, true);
String passwordSpecialChars = faker.internet()
.password(8, 16, true, true);
String passwordUpperCaseAndSpecialCharsAndDigits = faker.internet()
.password(8, 16, true, true, true);
// Lorem Ipsum
String randomString = faker.lorem()
.word();
String randomString = faker.lorem()
.character();
String randomStringLengthFixed = faker.lorem()
.character(21);
Data Faker를 이용한 사용자 생성 테스트
이제 기존 사용자 생성 테스트에서 하드코딩된 입력값이 아닌 무작위 값을 넣을 수 있다.
@Test
void User_인스턴스를_생성한다() {
// given
String email = faker.internet()
.emailAddress();
String password = faker.internet()
.password(8, 40, true, true, true);
String nickname = faker.funnyName()
.name();
// when
User user = User.builder()
.passwordEncoder(new BCryptPasswordEncoder())
.email(email)
.password(validPassword)
.nickname(validNickname)
.build();
// then
assertThat(user).extracting("email", "nickname")
.containsExactly(email, nickname);
}
매번 테스트가 실행될 때마다, 테스트는 무작위 데이터를 매번 다르게 생성해서 사용할 것이다. 오늘은 놓칠 수도 있지만, 매번 빌드할 때마다 통과하지 못하는 케이스를 발견할 수 있다! 다른 기능을 개발하고 그 기능을 개발을 하면서도, 과거에 작성했던 다른 기능의 버그를 빌드 시에 잡아낼 수도 있다.
최근엔 협업을 진행하며 코드를 병합할 때 CI 과정으로 빌드 테스트 자동화는 필수다. 메인 브랜치로 병합하기 전에 자동화된 CI 파이프라인을 진행하다 미처 생각하지 못했던 버그를 발견해 낼 수 있고, 버그가 있음에도 항상 통과만 하는 테스트 작성에서 더욱 의미 있는 테스트를 작성할 수 있다.
'Spring > 라이브러리' 카테고리의 다른 글
Flyway를 이용한 로컬 환경 더미 데이터 생성 (0) | 2024.04.06 |
---|---|
Flyway로 DB 마이그레이션 (0) | 2024.04.05 |