List<String> list =List.of("A","B","C");assertThat(list).hasSize(3).contains("A","B").containsExactly("A","B","C")// 순서 포함 정확히 일치.doesNotContain("D").isNotEmpty();
// 기본 방법 — 필드를 각각 검증 (가독성 저하)assertThat(member.getNickname()).isEqualTo("김철수");assertThat(member.getAge()).isEqualTo(30);// hasFieldOrPropertyWithValue — 하나의 체인으로 개선assertThat(member).hasFieldOrPropertyWithValue("nickname","김철수").hasFieldOrPropertyWithValue("age",30);
List<Post> posts = postService.findAll();// 단일 필드 추출assertThat(posts).extracting("title").containsExactly("제목1","제목2","제목3");// 여러 필드 동시 추출assertThat(posts).extracting("title","status").containsExactly(tuple("제목1","PUBLISHED"),tuple("제목2","DRAFT"));
Post expected =newPost("제목","내용","DRAFT");Post actual = postService.create(command);// equals() 오버라이드 없이 전체 필드 비교assertThat(actual).usingRecursiveComparison().ignoringFields("id","createdAt").isEqualTo(expected);
// 문제: 첫 번째 검증 실패 → 이후 검증은 실행되지 않음assertThat(member).hasFieldOrPropertyWithValue("nickname","nickname")// 실패 → 즉시 종료.hasFieldOrPropertyWithValue("age",30)// 실행 안 됨.hasFieldOrPropertyWithValue("useAgreement",false);// 실행 안 됨
// SoftAssertions — 모든 검증을 실행한 뒤 한꺼번에 실패 보고assertSoftly(softly ->{ softly.assertThat(member.getNickname()).isEqualTo("김철수"); softly.assertThat(member.getAge()).isEqualTo(30); softly.assertThat(member.isUseAgreement()).isTrue();});// 모든 실패가 한 번에 보고됨
// 예외 발생 검증assertThatThrownBy(()-> postService.findById(999L)).isInstanceOf(ResourceNotFoundException.class).hasMessageContaining("999");// 예외 없음 검증assertThatCode(()-> postService.create(validCommand)).doesNotThrowAnyException();
assertThat(post.getStatus()).as("게시글 상태 검증").isEqualTo(PostStatus.PUBLISHED);// 실패 시: [게시글 상태 검증] expected: PUBLISHED but was: DRAFT