본문 바로가기
📚Framework & Library/JUnit

[Junit] Test 종류. Test Case (feat. 전자정부 프레임워크)

by inbeom 2023. 11. 17.
728x90
테스트는 소프트웨어 개발 생명주기에서 매우 중요한 부분을 차지한다. 테스트를 잘 하면 버그 감소와 유지보수 용이성, 코드 문서화, 개발 생산성 향상 등의 측면에서 유리하다.

 

 

 

White Box Test (구조 기반 테스트)

  • 소프트웨어의 내부 구조와 동작을 검증하는 테스트로 개발자가 코드의 내부 로직, 제어 흐름, 데이터 흐름 등을 이해하고 테스트 케이스를 작성하는 방법이다.
  • 코드의 모든 경로와 조건을 확인할 수 있어 Code Coverage가 높지만, 개발자의 시각에 의존하므로 완전한 테스트는 힘들다.

Black Box Test (기능 기반 테스트)

  • 소프트웨어의 내부 구현을 알지 못하고 기능에만 초점을 맞춘 테스트로 시스템이 요구 사항을 만족하는지 여부를 확인하는 것이 목표이다. 
  • 사용자의 관점에서 테스트하기 때문에 완전한 기능 검증이 가능하지만, 코드의 모든 경로를 테스트하지 못할 수 있고 특정한 버그나 예외 상황을 놓칠 수 있다.
주로, 개발자는 White Box Test를 수행하고, QA(Quality Assurance) 팀은 Black Box Test를 수행하여 다양한 시각에서 소프트웨어를 검증한다.

 

 

White Box (Unit) Test - 종류

Junit을 사용하여 Test Case를 작성할 때 주로 사용하는 테스트 방법.

 

1. Method Test 

Unitils 3.4

    @Test
    public void testAddNumbers() {
        // given
        MyService myService = new MyService();
        // when
        int result = myService.addNumbers(2, 3);
        // then
        ReflectionAssert.assertReflectionEquals(5, result);
    }

 

2. API Test

RestAssured 4.5.0

    @Test
    public void testGetUser() {
        // given
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
        // when
        Response response = given()
                .when()
                .get("/users/1")
                .then()
                .statusCode(200)
                .extract()
                .response();
        // then
        String username = response.path("username");
        given()
                .when()
                .get("/users/1")
                .then()
                .body("username", equalTo(username));
    }

 

3. Database Test

Unitils 3.4

    @Test
    public void testFindUserById() {
        // given
        UserDao userDao = new UserDao(entityManager);
        // when
        User user = userDao.findUserById(1L);
        // then
        assertEquals("John", user.getName());
        assertEquals("Doe", user.getSurname());
        assertEquals("john@example.com", user.getEmail());
    }

 

4. Integration Test

MockMvc

    @Test
    public void testGetHello() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string("Hello, World!"));
    }

 

5. Suite Test

@RunWith(Suite.class)
@Suite.SuiteClasses({
        TestClass1.class,
        TestClass2.class,
        TestClass3.class
})
public class TestSuite {
}

 

 

코드 검증 방법

전자정부 프레임워크 샘플

 

Constructor Test

단순한 로직의 경우 테스트 하지 않아도 되지만, 값을 초기화 하거나 로드하는 경우에는 테스트를 수행한다.

 

Setter / Getter Test

단순한 Set/Get은 테스트 하지 않아도 되지만, 로직이 있는 경우 별도의 메서드로 분리하고 테스트 한다.

 

Boundary Test

Null 체크, Default 값 확인, 범위가 있는 경우 MIN/MAX 값에 대한 확인을 목적으로 테스트 한다.

*결국 NPE가 발생하지 않도록 보완하는 것이 좋다.

 

Exception Test

예상하는 예외가 실제로 발생하는지 확인한다. 

@Test (expected = IndexOutOfBoundsException.class)
public void testException() {
       throw new IndexOutOfBoundsException();
}

 

Equality Test 

결과 값이 예상한 값과 일치하는지 비교한다.

// Value
@Test
public void testReferenceEqual() {
      String string1 = new String("somevalue");
      String string2 = string1;
      assertEquals("두 객체의 값이 같음", string1, string2); 
      assertSame("두 객체의 주소값이 같음", string1, string2);    
}

// Number
@Test
public void testDoubleEqual() {
      double value1 = 10 / 3;
      double value2 = 3.33;
      assertEquals("소수 둘째자리까지 같음", value1, value2, 2);
}

// List / Array
@Test
public void testReflectionEqualLenientOrder() {
      List<Integer> myList = Arrays.asList(3, 2, 1);
      assertReflectionEquals(Arrays.asList(3, 2, 1), myList);
      assertReflectionEquals("순서 무시하고 값이 같은지 비교", Arrays.asList(1, 2, 3), myList, LENIENT_ORDER);
}
 
@Test
public void testAssertReflectionEqualsIgnoringDefault() {
      assertReflectionEquals("디폴트 값 무시하고 같은지 비교",
                                    new UserVo(1, "name", null), new UserVo(1, "name", "description1"), IGNORE_DEFAULTS);
}

// Value Object 
@Test
public void testAssertReflectionEqualsFieldByField() {
 
      UserVo user1 = new UserVo(100, "name", "description");
      UserVo user2 = new UserVo(100, "name", "description");
 
      assertReflectionEquals("객체를 구성하는 attribute를 하나하나 자동으로 비교", user1, user2);
}

 

Parameterized Test

파라미터 값만 바꿔가면서 동일한 테스트를 반복해서 수행한다. 

@RunWith(Parameterized.class)
public class ParameterizedTest {
 
     private String password;
     private boolean isValid;
     private static PasswordValidator validator;
 
     @BeforeClass
     public static void setUp() {
          validator = new PasswordValidator();
     }
 
     public ParameterizedTest(String password, boolean isValid) {
          this.password = password;
          this.isValid = isValid;
     }
 
     @Parameters
     public static Collection passwords() {
          return Arrays.asList(new Object[][] { { "1234qwer", true }, {"12345678", false}, {"1q2w3e4r", true} });
     }
 
     @Test
     public void isValidPasswordWithParams() {
          assertEquals(validator.isValid(this.password), this.isValid);
     }
}

 

Timeout Test

테스트에 소요되는 시간을 지정하여, 해당 시간이 넘은 경우 Fail 처리한다.

@Test (timeout = 1)
public void testTimeout() {
}

 

Test Ignore

테스트를 Skip 하고 싶을 때 사용한다. (Class / Method에 적용 가능)

@Ignore ("테스트 수행하지 않도록 설정 함 (실제론 상세 원인을 표시)")
@Test
public void testIgnore() {
    assertTrue("이 테스트 메소드는 실행이 되지 않음", true);
}

 

 

※ 테스트에 사용되는 라이브러리들은 해당 URL참조.
https://inbeom.tistory.com/entry/API-%ED%85%8C%EC%8A%A4%ED%8A%B8-junit4-AssertJ

 

 

- 끝 -

            

 

reference.

https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:dev:tst:test_case

 

728x90