๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป๐Ÿ“/ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

[Trouble Shooting] ItemTest ํ…Œ์ŠคํŠธ์ฝ”๋“œ ๊ด€๋ จ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

_silver 2024. 12. 18. 21:35

์ด๋ฒˆ ํ”Œ๋Ÿฌ์Šค์ฃผ์ฐจ ๊ฐœ์ธ๊ณผ์ œ๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด JPA์‹ฌํ™”, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ์„ฑ๋Šฅ์ตœ์ ํ™” ๊ฐœ๋…๋“ค์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง„ํ–‰๋˜์—ˆ๋‹ค.

 

๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๋˜ ์ค‘ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์‹คํ–‰ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

 

[Github ๋งํฌ]

 


1. ๋ฌธ์ œ ์ƒํ™ฉ

๐Ÿ“ ItemTest ํด๋ž˜์Šค์—์„œ ์˜ˆ์™ธ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ ์‹คํŒจ

item.setStatus(null);

- ItemTest ํด๋ž˜์Šค์—์„œ status ํ•„๋“œ๋ฅผ null๋กœ ์„ค์ •ํ•˜๋ฉด PersistenceException์ด ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ๋‹ค.

- ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฒฐ๊ณผ, AssertionError๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.[๋”๋ณด๊ธฐ ์ฐธ๊ณ ]

๋”๋ณด๊ธฐ

๐Ÿ˜ข [๋ฌธ์ œ ์ฝ”๋“œ] : ItemTest ํด๋ž˜์Šค

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class ItemTest {

    @Autowired
    private ItemRepository itemRepository;

    @Test
    @DisplayName("status ๊ฐ’์ด null์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ ํ™•์ธ ")

    // status ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ ์ง„ํ–‰
    void statusIsEmpty_shouldFail() {
        Item item = new Item();
        item.setName("Test Item");
        item.setDescription("Test Description");
        item.setStatus(null);

        // ์–ด๋–ค ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ™•์ธ
        assertThatThrownBy(() -> itemRepository.saveAndFlush(item))
                .isInstanceOf(PersistenceException.class);

    }

 

๐Ÿšจ [์—๋Ÿฌ ๋ฉ”์„ธ์ง€] ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฒฐ๊ณผ

java.lang.AssertionError: 
Expecting code to raise a throwable.

 

 


2. ์›์ธ ๋ถ„์„

1) Hibernate์˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ • ๋ฌธ์ œ

- Item ํด๋ž˜์Šค์˜ status ํ•„๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •๋˜์–ด ์žˆ์—ˆ๋‹ค.

@Column(nullable = false, columnDefinition = "varchar(20) default 'PENDING'")
private String status;

โ“ ๋ฌธ์ œ์ 

- @Column(์ƒ๋žต....)์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•  ๋•Œ ์ ์šฉ๋˜๋Š” SQL ์ œ์•ฝ์กฐ๊ฑด์ด๋‹ค.

Hibernate๋‚˜ JPA๋Š” ๊ธฐ๋ณธ๊ฐ’์„ ์ ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

- ๋”ฐ๋ผ์„œ, status ํ•„๋“œ๊ฐ’์€ null์ด ์„ค์ •๋œ ์ƒํƒœ ๊ทธ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ „๋‹ฌ๋˜์–ด PersistenceException์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

 

2) @DataJpaTest์˜ ํŠน์„ฑ ๊ฐ„๊ณผ

- @DataJpaTest๋Š” JPA Repository๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š”๋ฐ ์ตœ์ ํ™”๋œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

- ํ•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ œ์•ฝ์กฐ๊ฑด์„ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ง์ ‘ SQL์„ ์‹คํ–‰์„ ๊ฒ€์ฆํ•˜๊ธฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์•˜๋‹ค.


3. ํ•ด๊ฒฐ๋ฐฉ์•ˆ

ItemTest ํด๋ž˜์Šค์—์„œ JPA Repository๋ฅผ ์‚ฌ์šฉํ•ด status ํ•„๋“œ์— null ๊ฐ’์„ ์„ค์ •ํ•œ ๋’ค ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ Repository ํ…Œ์ŠคํŠธ๋งŒ์œผ๋กœ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ œ์•ฝ ์กฐ๊ฑด ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์›Œ

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด JPQL๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ItemJPQLTest ํด๋ž˜์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ ์ง„ํ–‰ํ–ˆ๋‹ค.

 

 ItemJPQLTest ํด๋ž˜์Šค๋Š” EntityManager๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ status ํ•„๋“œ๋ฅผ ๊ฐ•์ œ๋กœ null๋กœ ์„ค์ •ํ•˜๋Š” JPQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ–ˆ๋‹ค.

๊ฐ•์ œ๋กœ null์„ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— NOT NULL ์ œ์•ฝ ์กฐ๊ฑด์ด ์ž‘๋™ํ•˜์—ฌ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

// ๊ฐ•์ œ null ์ ์šฉ
assertThatThrownBy(() -> {
    int updatedCount = entityManager.createQuery(
                    "UPDATE Item i SET i.status = null WHERE i.id = :id")
            .setParameter("id", item.getId())
            .executeUpdate();  //  ์ฟผ๋ฆฌ ์‹คํ–‰

}).isInstanceOf(PersistenceException.class);

 

๐Ÿ“Ž JPQL๊ณผ EntityManager์„ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”?

์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด Hibernate๊ฐ€ Repository๋ฅผ ํ†ตํ•ด ์ €์žฅํ•  ๋•Œ ๊ธฐ๋ณธ๊ฐ’์ด๋‚˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ์ ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋•Œ๋ฌธ์— ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ด์•ผ NOT NULL๊ณผ ๊ฐ™์€ ์ œ์•ฝ ์กฐ๊ฑด์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•˜๋‹ค.

๋”๋ณด๊ธฐ

๐Ÿ™‚ [์„ฑ๊ณต ์ฝ”๋“œ] : ItemJPQLTest ํด๋ž˜์Šค

@ActiveProfiles("test")
@SpringBootTest
@Transactional
class ItemJPQLTest {

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    @DisplayName("JPQL UPDATE๋ฅผ ์ด์šฉํ•˜์—ฌ status๋ฅผ null๋กœ ์„ค์ •์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ ํ™•์ธ")
    void updateStatusToNull_shouldNull() {
        Item item = new Item();
        item.setName("Test Item");
        item.setDescription("Test Description");
        item.setStatus("ACTIVE");

        entityManager.persist(item);
        entityManager.flush();      // ๊ฐ•์ œ ๋ฐ˜์˜

        // ๊ฐ•์ œ null ์ ์šฉ
        assertThatThrownBy(() -> {
            int updatedCount = entityManager.createQuery(
                            "UPDATE Item i SET i.status = null WHERE i.id = :id")
                    .setParameter("id", item.getId())
                    .executeUpdate();  //  ์ฟผ๋ฆฌ ์‹คํ–‰

        }).isInstanceOf(PersistenceException.class);

        }
    }

4. ๊ฒฐ๊ณผ

PersistenceException์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜์—ฌ ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผ๋˜์—ˆ๋‹ค.

 


5. ๋ฐฐ์šธ ์ 

์•„... ์ฒ˜์Œ์— ํ…Œ์ŠคํŠธ์ฝ”๋“œ ํŠน๊ฐ•์„ ๋ณด๊ณ  ๋ฌด์ž‘์ • @DataJpaTest๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , JPA Repository ํ…Œ์ŠคํŠธ์— ํŠนํ™”๋œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋ผ๊ณ  ํ•œ๋‹ค.(์ฒซ ๋‹จ์ถ”๋ถ€ํ„ฐ ์ž˜๋ชป ๋งž์ท„๋˜ ๊ฒƒ์ด๋‹ค.)

@DataJpaTest ์–ด๋…ธํ…Œ์ด์…˜์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์ตœ์†Œํ™”ํ•˜๊ณ  Repository ๊ธฐ๋Šฅ๋งŒ ๊ฒ€์ฆํ•˜๋Š”๋ฐ ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

 

EntityManager์™€ JPQL์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ ˆ๋ฒจ์—์„œ์˜ ์ œ์•ฝ ์กฐ๊ฑด ๊ฒ€์ฆ์„ ๋ช…ํ™•ํžˆ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.