33import static org .assertj .core .api .Assertions .assertThat ;
44import static org .assertj .core .api .SoftAssertions .assertSoftly ;
55import static org .junit .jupiter .api .Assertions .assertNotEquals ;
6- import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .*;
6+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .delete ;
7+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .get ;
8+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .post ;
9+ import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .put ;
710import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .content ;
811import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .status ;
912
1013import java .util .Optional ;
1114
1215import org .junit .jupiter .api .BeforeAll ;
16+ import org .junit .jupiter .api .DisplayName ;
1317import org .junit .jupiter .api .Test ;
1418import org .springframework .beans .factory .annotation .Autowired ;
1519import org .springframework .http .MediaType ;
2327import in .koreatech .koin .acceptance .fixture .UserAcceptanceFixture ;
2428import in .koreatech .koin .admin .abtest .model .Abtest ;
2529import in .koreatech .koin .admin .abtest .model .AbtestVariable ;
30+ import in .koreatech .koin .admin .abtest .model .AccessHistory ;
2631import in .koreatech .koin .admin .abtest .model .AccessHistoryAbtestVariable ;
2732import in .koreatech .koin .admin .abtest .model .Device ;
2833import in .koreatech .koin .admin .abtest .repository .AbtestRepository ;
34+ import in .koreatech .koin .admin .abtest .repository .AccessHistoryRepository ;
2935import in .koreatech .koin .admin .abtest .repository .DeviceRepository ;
3036import in .koreatech .koin .admin .manager .model .Admin ;
3137import in .koreatech .koin .domain .owner .model .Owner ;
3238import in .koreatech .koin .domain .student .model .Department ;
3339import in .koreatech .koin .domain .student .model .Student ;
40+ import jakarta .persistence .EntityManager ;
41+ import jakarta .persistence .PersistenceContext ;
3442
3543class AbtestApiTest extends AcceptanceTest {
3644
@@ -55,6 +63,12 @@ class AbtestApiTest extends AcceptanceTest {
5563 @ Autowired
5664 private DepartmentAcceptanceFixture departmentFixture ;
5765
66+ @ Autowired
67+ private AccessHistoryRepository accessHistoryRepository ;
68+
69+ @ PersistenceContext
70+ EntityManager em ;
71+
5872 private Admin admin ;
5973 private String adminToken ;
6074 private Department department ;
@@ -549,4 +563,26 @@ void setUp() {
549563 String responseBody2 = mvcResult2 .getResponse ().getContentAsString ();
550564 assertNotEquals (responseBody , responseBody2 );
551565 }
566+
567+ @ Test
568+ @ DisplayName ("디바이스가 없는 접속 이력을 조회할 때 INNER JOIN으로 인한 누락을 검증한다" )
569+ void 디바이스_없는_이력_조회_테스트 () {
570+ // given
571+ // 1. 디바이스가 없는 AccessHistory를 생성해서 저장합니다.
572+ AccessHistory history = AccessHistory .create ();
573+ accessHistoryRepository .save (history );
574+
575+ // 2. 영속성 컨텍스트를 비워 실제 DB 쿼리가 나가도록 유도합니다.
576+ em .flush ();
577+ em .clear ();
578+
579+ // when
580+ Optional <AccessHistory > result = accessHistoryRepository .findById (history .getId ());
581+
582+ // then
583+ // INNER JOIN -> 결과가 비어있음(실패)
584+ // LEFT JOIN -> 결과에 포함됨(성공)
585+ assertThat (result ).isPresent ();
586+ assertThat (result .get ().getId ()).isEqualTo (history .getId ());
587+ }
552588}
0 commit comments