<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yaho.log</title>
        <link>https://velog.io/</link>
        <description>야호!</description>
        <lastBuildDate>Wed, 27 Jul 2022 14:33:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yaho.log</title>
            <url>https://velog.velcdn.com/images/pup-paw/profile/8a705724-0a09-4807-93c2-2b972bb1bf24/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yaho.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/pup-paw" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[테스트 격리]]></title>
            <link>https://velog.io/@pup-paw/test-isolation</link>
            <guid>https://velog.io/@pup-paw/test-isolation</guid>
            <pubDate>Wed, 27 Jul 2022 14:33:36 GMT</pubDate>
            <description><![CDATA[<h1 id="테스트-격리">테스트 격리</h1>
<h2 id="🧐-테스트-격리란">🧐 테스트 격리란?</h2>
<ul>
<li><p>테스트가 순서에 상관없이 독립적으로 실행되며 결정적으로 수행되야 함</p>
</li>
<li><p>같은 입력 값이면 언제나 어떤 순서라도 같은 결과를 반환해야 함</p>
</li>
<li><p>멱등하다는 의미도 포함하고 있음</p>
</li>
</ul>
<h2 id="🤔-테스트를-왜-격리해야-하는가">🤔 테스트를 왜 격리해야 하는가?</h2>
<h3 id="내가-느낀-이유">내가 느낀 이유</h3>
<ul>
<li>새로운 테스트가 기존 테스트에 영향을 주지 않게하기 위해서</li>
</ul>
<h3 id="검색을-통해-알게된-이유">검색을 통해 알게된 이유</h3>
<ul>
<li><p>테스트들이 서로 순서에 상관 없이 독립적으로 수행되어야 하기 때문에</p>
</li>
<li><p>마틴 파울러는 비결정적 테스트의 문제점에 대해 언급하며 그 원인으로 테스트 격리의 부족을 이야기했다고 함</p>
<ul>
<li><input disabled="" type="checkbox"> 비결정적 테스트가 뭘까?? ❓</li>
</ul>
</li>
</ul>
<h2 id="🤨-계층별-테스트-격리-방법">🤨 계층별 테스트 격리 방법</h2>
<h3 id="domain">domain</h3>
<ul>
<li><p>테스트 격리가 필요 없음</p>
<ul>
<li><p>서로 다른 테스트에서같은 객체를 사용하지 않도록 하거나</p>
</li>
<li><p>공통 fixture를 사용할 경우 @BeforeEach 를 사용해 초기화</p>
</li>
</ul>
</li>
</ul>
<h3 id="repository">repository</h3>
<ul>
<li><p>@DataJpaTest</p>
<ul>
<li><p>데이터 계층에 관련된 빈들만 가지고 slice 테스트</p>
<ul>
<li><input disabled="" type="checkbox"> slice 테스트란? ❓</li>
</ul>
</li>
<li><p>DB에 접근하기는 함 </p>
</li>
<li><p>해당 어노테이션을 사용하면 InMemory에서 실행되며 자동으로 @Transactional 어노테이션이 적용됨</p>
<ul>
<li><p><input disabled="" type="checkbox">  InMemory가 뭐지? ❓</p>
</li>
<li><p><input disabled="" type="checkbox">  @Transactional 이란? ❓</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="service">service</h3>
<ul>
<li><p>@Transactional</p>
<ul>
<li><p>기본전략이 트랜잭션 rollback </p>
</li>
<li><p>실제로는 데이터베이스의 상태를 변화시키지 않고 격리된 상황에서 테스트</p>
</li>
</ul>
</li>
<li><p>Mock 프레임워크</p>
<ul>
<li><p>실제 DB 근처에는 접근도 하지 않음</p>
</li>
<li><p>테스트 격리를 신경쓰지 않고 테스트할 수 있음</p>
</li>
<li><p><input disabled="" type="checkbox">  Mock 프레임워크가 뭐지? ❓
💡hint: Mockito…</p>
</li>
</ul>
</li>
</ul>
<h3 id="controller">controller</h3>
<ul>
<li><p>Mock 프레임워크</p>
<ul>
<li><p>MockMvc : Rest API 클라이언트 도구</p>
</li>
<li><p><input disabled="" type="checkbox">  @SpringBootTest vs @WebMvcTest ❓
💡hint: @WebMvcTest는 @DataJpaTest와 마찬가지로 해당 계층에 관련된 빈들만 가지고 slice 테스트 가능</p>
</li>
</ul>
</li>
</ul>
<h3 id="인수-테스트">인수 테스트</h3>
<ul>
<li><p><del>@Transactional</del></p>
<ul>
<li><p>인수 테스트에서는 사용할 수 없는 방법</p>
</li>
<li><p>@SprintBootTest 에서는 port 를 지정해 서버를 띄움</p>
</li>
<li><p>이때 HTTP 클라이언트와 서버는 각각 다른 스레드에서 실행됨</p>
</li>
<li><p>따라서 호출되는 쪽은 다른 트랜잭션으로 커밋되기 때문에 해당 어노테이션이 무의미함</p>
</li>
</ul>
</li>
<li><p>DELETE query</p>
<ul>
<li><p>@BeforeEach에서 테스트에 필요한 데이터를 생성하고 @AfterEach에서 데이터 삭제 요청을 보내는 방법 </p>
</li>
<li><p>테스트에 필요한 데이터가 적은 경우 용이할 수 있음</p>
</li>
<li><p>하지만 필요한 데이터의 양이 많거나, 연관관계가 복잡한 경우 굉장한 비효율이 발생할 수 있음</p>
</li>
</ul>
</li>
<li><p>TRUNCATE query</p>
<ul>
<li><p>매 테스트 이후 모든 테이블을 초기화하는 방법</p>
<ul>
<li><p><input disabled="" type="checkbox">  DELETE vs TRUNCATE ❓</p>
</li>
<li><p>DELETE query에 비해 좋은 이유</p>
</li>
<li><p>JPA의 경우 DELETE 요청이 오면 바로 DELETE를 하는 것이 아니라 SELECT로 조회 후 DELETE를 함</p>
<ul>
<li><input disabled="" type="checkbox"> 왜? ❓</li>
</ul>
</li>
<li><p>삭제를 수행할 때 트랜잭션 로그 공간을 적게 사용</p>
</li>
<li><p>DELETE는 행마다 lock을거는데 비해 TRUNCATE은 lock을 거는 수가 상대적으로 적은 시간에 테이블 초기화</p>
<ul>
<li><input disabled="" type="checkbox"> lock이 뭐지? ❓</li>
</ul>
</li>
</ul>
</li>
<li><ol>
<li>@Sql 사용</li>
</ol>
<ul>
<li><p>스프링부트에서 제공하는 어노테이션</p>
</li>
<li><p>클래스 테스트가 실행되기 전에 @Sql이 가리키는 경로에 있는 SQL 실행이 먼저 일어남</p>
</li>
<li><p>따라서 이 파일안에 모든 테이블에 대한 TRUNCATE SQL을 미리 작성</p>
</li>
<li><p>하지만 엔티티 또는 연관관계 테이블이 추가될 때마다 파일을 수정해줘야 하는 단점이 있음</p>
</li>
</ul>
</li>
<li><ol start="2">
<li>EntityManager 사용</li>
</ol>
<ul>
<li><p>JPA에서 쿼리를 직접 만들 수 있는 EntityManager를 빈으로 주입</p>
</li>
<li><p>모든 테이블 이름을 조사해서 각각의 인수테스트가 시작할 때 TRUNCATE 쿼리를 실행시키는 방식</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>@DirtiesContext</p>
<ul>
<li><p>현재 테스트가 실행되려는 컨텍스트에 이미 빈이 올라가 있으면 Dirties를 확인하고 컨텍스트를 새로 로드하는 방법</p>
</li>
<li><p>하지만 매번 테스트 하기전에 컨텍스트를 다시 로드하게 되면 테스트하는데 시간이 오래걸림</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>