๋ฐ˜์‘ํ˜•
๐Ÿ“์ด์ „๊ธ€
[Fixture Monkey] ํ”ฝ์Šค์ณ ๋ชฝํ‚ค๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ (Java Spring)

 

 

๐Ÿ”น ํ™˜๊ฒฝ ์„ค์ •

๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ์•„๋ž˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

fixture-monkey-starter์— ์ด๋ฏธ ํฌํ•จ๋˜์–ด์žˆ์–ด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.0")

 

 

๐Ÿ”น ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋งŒ๋“ค๊ธฐ

1. ํ…Œ์ŠคํŠธํ•  ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ

์˜๋ฏธ์—†๋Š” ๊ฐ์ฒด๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š”๊ฒƒ์€ ์žฌ๋ฏธ์—†์–ด, Entity ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  Repository ๊ธฐ๋Šฅ์ด ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด DB ๋“ฑ ์„ค์ •์ด ํ•„์š”ํ•œ๋ฐ, ์–ด๋ ต๋‹ค๋ฉด @Entity๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์‚ฌ์šฉํ•˜์…”๋„๋ฉ๋‹ˆ๋‹ค.

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@ToString
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @NotBlank
    String name;

    @NotNull
    @Min(value = 10)
    Integer price;

    @NotNull
    @PastOrPresent
    Instant createdAt;
}

public interface BookRepository extends JpaRepository<Book, Long> {
}

 

 

2. Fixture Monkey ์—†์ด ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธํ•˜๊ณ ์ž ํ•˜๋Š” ๊ด€์‹ฌ ๊ธฐ๋Šฅ์ด ์—ฌ๋Ÿฟ ํฌํ•จ๋œ ํ…Œ์ŠคํŠธ์ด์ง€๋งŒ, Validation ๊ด€์ ์—์„œ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์„๊ฒƒ ๊ฐ™์•„ ์•„๋ž˜์™€๊ฐ™์ด ์ž‘์„ฑํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Validation์— ํ•ฉ๋‹นํ•œ ๊ฐ’์ด ๋“ค์–ด์˜ค๋ฉด ๋กœ์ง์ด ๊ธฐ๋Œ€ํ•˜๋Š”๋ฐ๋กœ ์ˆ˜ํ–‰๋˜๊ณ , ๊ทธ๋ ‡์ง€ ๋ชปํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@DataJpaTest
class BookRepositoryTest {
    @Autowired
    BookRepository bookRepository;

    @Test()
    void ์ผ๋ฐ˜_ํ…Œ์ŠคํŠธ() {
        Book book = Book.builder()
                .id(1L)
                .name("ํ…Œ์ŠคํŠธ์šฉ์ฑ…")
                .price(10000)
                .createdAt(Instant.now().minus(1, ChronoUnit.DAYS))
                .build();
        bookRepository.save(book);

        Book savedBook = bookRepository.findById(1L).orElseThrow(EntityNotFoundException::new);

        assertThat(savedBook).usingRecursiveComparison()
                .ignoringFields("createdAt")
                .isEqualTo(book);
        assertThat(savedBook.getCreatedAt()).isCloseTo(book.getCreatedAt(), within(3, ChronoUnit.SECONDS));
    }

    @Test()
    void ์ผ๋ฐ˜_์‹คํŒจ_ํ…Œ์ŠคํŠธ() {
        Book book = Book.builder()
                .id(1L)
                .name("ํ…Œ์ŠคํŠธ์šฉ์ฑ…")
                .price(1) // exception
                .createdAt(Instant.now().minus(1, ChronoUnit.DAYS))
                .build();

        assertThatThrownBy(() -> bookRepository.save(book))
                .isInstanceOf(ConstraintViolationException.class);
    }
}

 

 

3. Fixture Monkey๋ฅผ ์ด์šฉํ•œ ํ…Œ์ŠคํŠธ

์•„๋ž˜ ์ฝ”๋“œ๋Š” ๊ฐ์ฒด ์ƒ์„ฑ์„ Fixture Monkey์—๊ฒŒ ์œ„์ž„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋žœ๋คํ•˜๊ฒŒ ์ƒ์„ฑ๋œ๋‹ค๋Š” ํŠน์ง• ๋•Œ๋ฌธ์— @Test๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฐ˜๋ณตํ•˜์—ฌ ์„ฑ๊ณตํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ ์ž @RepeatedTest๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

@DataJpaTest
class BookRepositoryTest {
    @Autowired
    BookRepository bookRepository;

    @RepeatedTest(5)
    void Fixture_Monkey_ํ…Œ์ŠคํŠธ() {
        FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
                .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
                .plugin(new JakartaValidationPlugin())
                .build();
        Book book = fixtureMonkey.giveMeOne(Book.class);

        Book savedBook = bookRepository.save(book);
        System.out.println(savedBook);

        assertThat(Validation.buildDefaultValidatorFactory()
                .getValidator()
                .validate(savedBook))
                .isEmpty();
    }
}

ํ…Œ์ŠคํŠธ๋Š” ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๋ฉฐ print ์‹œ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ„๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

์‚ฌ์šฉ๋ฒ•๋„ ์‰ฝ๊ณ  ์•Œ์•„์„œ ๋‹ค ํ•ด์ฃผ๋Š” ๋งŒ์กฑ์Šค๋Ÿฌ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•

BELATED ARTICLES

more