inblog logo
|
sxias
    REST APIJUnit Test

    [REST API] 19. Blog V3 : Integration Test

    문정준's avatar
    문정준
    May 15, 2025
    [REST API] 19. Blog V3 : Integration Test
    Contents
    Integration Test (통합 테스트)💡 통합 테스트 vs 화이트박스 테스트 (WhiteBox Testing)
    💡

    Integration Test (통합 테스트)

    1. 로컬에서 테스트 하는 환경이 실제 환경에서도 적용되는 지 확인하기 위함
    1. 코드를 수정하였을 때에 다른 코드에 영향이 있는지 확인하기 위함
     
    [Test] 유닛 테스트(Unit Test), 통합 테스트(Integration Test), 기능 테스트(Functional Test)란?
    세 줄 요약 유닛 테스트: 함수 하나하나와 같이 코드의 작은 부분을 테스트하는 것 통합 테스트: 서로 다른 시스템들의 상호작용이 잘 이루어 지는지 테스트하는 것 기능 테스트: 사용자와 어플리케이션의 상호작용이 원활하게 이루어지는지 테스트하는 것 서론 개발을 하다 보면 내 코드가 잘 동작하고 있는지 버그가 없는지 테스트하고 싶을 때가 있다. 그럴 때 '어떻게 테스트를 하면 좋을까..?'라는 생각을 하게 되고 테스트를 하는 방법과 종류에 대해 찾게 된다. 테스트를 범위에 따라 분류해보면 유닛 테스트, 통합 테스트, 기능 테스트로 나눠 볼 수 있다. 그림으로 표현하자면 위와 같이 표현할 수 있다. Acceptance Test는 Integration Test와 같다고 보면 된다. 그림을 보면 유닛 테스트가 가장..
    [Test] 유닛 테스트(Unit Test), 통합 테스트(Integration Test), 기능 테스트(Functional Test)란?
    https://cjwoov.tistory.com/9
    [Test] 유닛 테스트(Unit Test), 통합 테스트(Integration Test), 기능 테스트(Functional Test)란?
     

    💡 통합 테스트 vs 화이트박스 테스트 (WhiteBox Testing)

    • 통합 테스트는 개별 모듈이 서로 잘 연동되어 전체 시스템이 제대로 작동하는 지 확인하는 테스트
    • 화이트박스 테스트는 시스템 내부 코드 구조를 알고 테스트를 진행하는 방식
      • 통합 테스트를 진행하는 방향 중 하나로 화이트박스 테스트를 진행할 수 있음
      • 통합 테스트 ≠ 화이트박스 테스트 ⇒ 통합 테스트 ⊂ 화이트박스 테스트
    [테스트] 2. 동적 테스트 종류 - 화이트박스, 블랙박스 테스트
    1. 화이트박스 테스트(White Box Test) - 모듈의 원시 코드(Source Code) 오픈 상태에 진행 - 원시 코드의 논리적인 모든 경로를 테스트 후 테스트 케이스 설계하는 방법 - 모듈 안 작동을 직접 관찰 가능 - 원시 코드의 모든 문장을 한 번 이상 실행함으로써 수행 2. 화이트박스 테스트 종류 - 기초 경로 검사(Base Path Testing) => 테스트 케이스 설계자가 절차적 설계의 논리적 복잡성 측정할 수 있게 해주는 테스트 - 제어 구조 검사(Control Structure Testing) => 조건 검사(Condition Testing) : 프로그램 모듈 내 논리적 조건 테스트하는 테스트 케이스 설계 기법 => 루프 검사(Loop Testing) : 프로그램의 반복(Loop..
    https://berkley.tistory.com/m/183#:~:text=1.%20%ED%99%94%EC%9D%B4%ED%8A%B8%EB%B0%95%EC%8A%A4%20%ED%85%8C%EC%8A%A4%ED%8A%B8(White%20Box%20Test)%20%2D%20%EB%AA%A8%EB%93%88%EC%9D%98,%EC%BD%94%EB%93%9C%EC%9D%98%20%EB%85%BC%EB%A6%AC%EC%A0%81%EC%9D%B8%20%EB%AA%A8%EB%93%A0%20%EA%B2%BD%EB%A1%9C%EB%A5%BC%20%ED%85%8C%EC%8A%A4%ED%8A%B8%20%ED%9B%84%20%ED%85%8C%EC%8A%A4%ED%8A%B8
    [테스트] 2. 동적 테스트 종류 - 화이트박스, 블랙박스 테스트
     
    • UserControllerTest
      • MockMvc, ObjectMapper 사용 : JSON 변환 후 fetch
      • Test의 Transactional : 테스트가 다 끝난 후 Rollback
        • 일반적 Transactional : 코드 실행이 다 끝난 후 Commit
      • andExpect : mvc를 통해 함수가 실행되고 난 결과를 예상 : 맞으면 통과, 틀리면 에러 발생
    // 컨트롤러 통합 테스트 @Transactional @AutoConfigureMockMvc // MockMvc 클래스가 IoC에 로드 | RestTemplate -> 자바스크립트의 fetch와 동일, 진짜 환경에 요청 가능 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) // MOCK -> 가짜 환경을 만들어 필요한 의존관계를 다 메모리에 올려서 테스트 public class UserControllerTest { @Autowired private ObjectMapper om; // json <-> java Object 변환 해주는 객체. IoC에 objectMapper가 이미 떠있음 @Autowired private MockMvc mvc; // 가짜 환경에서 fetch 요청하는 클래스 | RestTemplate -> 자바스크립트의 fetch와 동일, 진짜 환경에 요청 가능 private String accessToken; @BeforeEach public void setUp() { // 테스트 시작 전에 실행할 코드 System.out.println("setUp"); User ssar = User.builder() .id(1) .username("ssar") .build(); accessToken = JwtUtil.create(ssar); } @AfterEach public void tearDown() { // 끝나고 나서 마무리 함수 // 테스트 후 정리할 코드 System.out.println("tearDown"); } @Test public void join_test() throws Exception { // 이 메서드를 호출한 주체에게 예외 위임 -> 지금은 jvm 이다 // given -> 가짜 데이터 UserRequest.JoinDTO reqDTO = new UserRequest.JoinDTO(); reqDTO.setEmail("haha@nate.com"); reqDTO.setPassword("1234"); reqDTO.setUsername("haha"); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // {"username":"haha","password":"1234","email":"haha@nate.com"} // when -> 테스트 실행 ResultActions actions = mvc.perform( // 주소가 틀리면 터지고, json 아닌거 넣으면 터지고, 타입이 달라도 터지고. 따라서 미리 터진다고 알려줌 MockMvcRequestBuilders .post("/join") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) ); // eye -> 결과 눈으로 검증 String responseBody = actions.andReturn().getResponse().getContentAsString(); //System.out.println(responseBody); // {"status":200,"msg":"성공","body":{"id":4,"username":"haha","email":"haha@nate.com","createdAt":"2025-05-13 11:45:23.604577"}} // then -> 결과를 코드로 검증 // json의 최상위 객체를 $ 표기한다 actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(4)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("haha")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.email").value("haha@nate.com")); } @Test public void login_test() throws Exception { // given UserRequest.LoginDTO reqDTO = new UserRequest.LoginDTO(); reqDTO.setUsername("ssar"); reqDTO.setPassword("1234"); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/login") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then (jwt 길이만 검증) -> 길이 변환 가능. 패턴만 확인 actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.accessToken", matchesPattern("^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+$"))); } @Test public void update_test() throws Exception { // given UserRequest.UpdateDTO reqDTO = new UserRequest.UpdateDTO(); reqDTO.setEmail("ssar@gmail.com"); reqDTO.setPassword("1234"); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .put("/s/api/user") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("ssar")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.email").value("ssar@gmail.com")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); } @Test public void checkUsernameAvailable_test() throws Exception { // given String username = "ssar"; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .get("/api/check-username-available/{username}", username) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.available").value(false)); } }
     
    • BoardControllerTest
      • 테스트에 사용할 DB와 실제 배포를 진행할 때 사용할 DB는 구조는 동일하되 값이 달라야 함
      • 실제 환경에 맞출 수 있도록 테스트 전용으로 사용하는 DB를 teardown이라고 함
      • teardown은 SQL 코드 내에 모든 데이터 값을 초기화시키는 코드를 포함해야 함 : Rollback
    // SpringBootTest 내에는 @Transactional 미포함 : rollback을 위해 추가 -> 근본적 문제 해결 불가 @Transactional //@Sql("classpath:db/teardown.sql") - 테스트용 DB 데이터셋 사용 : 지금은 미진행 @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class BoardControllerTest { @Autowired private ObjectMapper om; @Autowired private MockMvc mvc; private String accessToken; @BeforeEach public void setUp() { // 테스트 시작 전에 실행할 코드 System.out.println("setUp"); User ssar = User.builder() .id(1) .username("ssar") .build(); accessToken = JwtUtil.create(ssar); } @AfterEach public void tearDown() { // 끝나고 나서 마무리 함수 // 테스트 후 정리할 코드 System.out.println("tearDown"); } @Test public void list_test() throws Exception { // given Integer page = 1; String keyword = "제목1"; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .get("/") .param("page", page.toString()) .param("keyword", keyword) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].id").value(16)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].title").value("제목16")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].content").value("내용16")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].isPublic").value(true)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].userId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.prev").value(0)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.next").value(2)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.current").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.size").value(3)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.totalCount").value(11)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.totalPage").value(4)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isFirst").value(false)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isLast").value(false)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.numbers", hasSize(4))); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.keyword").value("제목1")); } @Test public void getBoardDetail_test() throws Exception { // given Integer id = 4; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .get("/api/board/{id}/detail", id) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(4)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목4")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용4")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value(true)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isBoardOwner").value(false)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isLove").value(false)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(2)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("love")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveId").value(nullValue())); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].id").value(3)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].content").value("댓글3")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].username").value("ssar")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].isReplyOwner").value(false)); } @Test public void save_test() throws Exception { // given BoardRequest.SaveDTO reqDTO = new BoardRequest.SaveDTO(); reqDTO.setTitle("제목21"); reqDTO.setContent("내용21"); reqDTO.setIsPublic(true); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/s/api/board") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(21)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목21")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용21")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value(true)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); } @Test public void getBoardOne_test() throws Exception { // given Integer id = 1; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .get("/s/api/board/{id}", id) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목1")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용1")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value(true)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); } @Test public void update_test() throws Exception { // given Integer id = 1; BoardRequest.UpdateDTO reqDTO = new BoardRequest.UpdateDTO(); reqDTO.setTitle("제1"); reqDTO.setContent("내1"); reqDTO.setIsPublic(true); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .put("/s/api/board/{id}", id) .content(requestBody) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제1")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내1")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value(true)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); } }
     
    • ReplyControllerTest
    @Transactional @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class ReplyControllerTest { @Autowired private ObjectMapper om; @Autowired private MockMvc mvc; private String accessToken; @BeforeEach public void setUp() { // 테스트 시작 전에 실행할 코드 System.out.println("setUp"); User ssar = User.builder() .id(1) .username("ssar") .build(); accessToken = JwtUtil.create(ssar); } @AfterEach public void tearDown() { // 끝나고 나서 마무리 함수 // 테스트 후 정리할 코드 System.out.println("tearDown"); } @Test public void save_test() throws Exception { // given ReplyRequest.SaveDTO reqDTO = new ReplyRequest.SaveDTO(); reqDTO.setBoardId(1); reqDTO.setContent("댓글6"); String requestBody = om.writeValueAsString(reqDTO); System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/s/api/reply") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(6)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("댓글6")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boardId").value(1)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt", matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+"))); } @Test public void delete_test() throws Exception { // given Integer id = 1; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .delete("/s/api/reply/{id}", id) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body").value(nullValue())); } }
     
    • LoveControllerTest
    @Transactional @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class LoveControllerTest { @Autowired private ObjectMapper om; @Autowired private MockMvc mvc; private String accessToken; @BeforeEach public void setUp() { // 테스트 시작 전에 실행할 코드 System.out.println("setUp"); User ssar = User.builder() .id(1) .username("ssar") .build(); accessToken = JwtUtil.create(ssar); } @AfterEach public void tearDown() { // 끝나고 나서 마무리 함수 // 테스트 후 정리할 코드 System.out.println("tearDown"); } @Test public void saveLove_test() throws Exception { // given LoveRequest.SaveDTO reqDTO = new LoveRequest.SaveDTO(); reqDTO.setBoardId(3); String requestBody = om.writeValueAsString(reqDTO); // System.out.println(requestBody); // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .post("/s/api/love") .content(requestBody) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveId").value(4)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(1)); } @Test public void deleteLove_test() throws Exception { // given Integer id = 1; // when ResultActions actions = mvc.perform( MockMvcRequestBuilders .delete("/s/api/love/{id}", id) .header("Authorization", "Bearer " + accessToken) ); // eye String responseBody = actions.andReturn().getResponse().getContentAsString(); System.out.println(responseBody); // then actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200)); actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공")); actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(0)); } }
     

    Result

    • 정상 작동 시 오류 검출 없음
    notion image
     
    • 에러 검출 시 해당 테스트 부분의 오류 검출
    notion image
     
    Share article
    Contents
    Integration Test (통합 테스트)💡 통합 테스트 vs 화이트박스 테스트 (WhiteBox Testing)

    Sxias ㆍ a32176740@gmail.com

    RSS·Powered by Inblog