[RealCoding] Software Testing

윰지·2020년 7월 22일
0

RealCoding

목록 보기
5/6

Unit Test

Software Testing

소프트웨어를 검사해 주어진 입력 내용과 기대되는 출력 내용 간 차이를 확인하는 과정

Verification vs Validation

  1. Verification
    • 개발자가 의도한 대로 동작하는가
  2. Validation
    • 각각의 요구 사항에 부합하게 동작하는가

Unit Test(단위 테스트)

  1. 특징
    • 가장 작은 단위의 테스트
    • 개발 의도를 간단 명료하게 표현해 줌
    • 가장 빠름
    • 외부 요인에 영향을 받지 않음
  2. 장점
    • 테스트 코드량이 적다.
    • 개발자를 위한 코드 안내서 역할을 할 수 있다.
    • 코드 작성 중에도 반복적으로 실행해 볼 수 있다.

테스트 코드 예제

import org.junit.Test;
import static org.junit.Assert.*;

public class JunitSampleTest{ //Class 이름 끝에는 TEst를 붙여준다.
    @Test //Test Annotation
    public void testMethod(){ //Test Method
    	int sum = 10 + 20;
        assertEquals(30, sum, 0); //TestCode
    }
}

테스트는 테스트 프레임워크를 사용한다.

  1. CUnit
  2. JUnit
    Java 언어를 위한 단위 테스트 프레임워크
  3. PyUnit

JUnit Annotation

  1. @Test
    가장 기분이 되는 annotation으로 테스트하고자 하는 method에 선언한다.
@Test
public void testCase1() throws Exception{
	System.out.println("테스트 메소드를 지정함.");
}
  • Exception 처리
    기대(예상)하는 Exception이 발생하는지를 테스트한다.

    @Test(expected = IndexOutOfBoundsException.class)
    public void testIsEmptyGetIndexOutOfBoundException(){
    	new ArrayList<Object>().get(0);
     }
  • timeout
    주어진 시간내에 정상적으로 실행이 되는지를 테스트 한다.

    @Test(timeout=5000)
    public void timeinMethodTest() throws InterruptedException{
    	Thread.sleep(3000);
    }
    
    @Test(timeout=5000)
    public void timeinMethodTest() throws InterruptedException{
    	Thread.sleep(6000);
    }
  1. @BeforeClass, @AfterClass
    해당 테스트 class가 실행전과 후에 동작할 class를 선언한다. static선언 필요
@BeforeClass
public static void setUpBeforeClass() throws Exception{
	System.out.println("테스트 수행 전 한번만 실행 됨.");
}

@AfterClass
public static void setUpBeforeClass() throws Exception{
	System.out.println("테스트 수행 후 한번만 실행 됨.");
}
  1. @Before, @After
    class내 test method들이 실행되기 전과 후에 동작할 method를 선언한다.
@Before
public static void setUp() throws Exception{
	System.out.println("테스트 케이스를 실행할 때마다 먼저 반복 실행 됨.");
}

@After
public static void tearDown() throws Exception{
	System.out.println("테스트 케이스를 실행할 때마다 수행 후 반복 실행 됨.");
}
  1. @FixMethodOrder
    테스트가 실행되는 순서를 정의한다.
  2. @SuiteClasses(Class[])
    체스트 클래스들을 묶어서 실행할 때 사용한다.
  3. @Ignore
    테스트를 진행하지 않을 때 사용한다.

@BeforeClass, @AfterClass, @Before, @After Flow

JUnit 단정문

  1. assert*
  • JUnit에서 사용되는 단정문과 hamcrest 단정문이 있다.
  • JUnit 4.x부터 hamcrest가 포함되어 바로 사용할 수 있다.
Method내용
assertTrue(a)a의 조건이 참이면 Pass
assertFalse(a)a의 조건이 참이면 Pass
assertEquals(a, b)a의 조건이 참이면 Pass
assertSame(a, b)a의 조건이 참이면 Pass
assertNotNull(a)a의 조건이 참이면 Pass
assertArrayEquals(a, b)a의 조건이 참이면 Pass

Hamcrest - assertThat

Matcher 라이브러리 중 하나로 테스트 표현식 작성시 좀 더 자연스로운 문맥과 문장을 만들 수 있도록 지원한다. 가장 큰 장점은 오류 메시지를 읽기가 쉽다.

public class JunitHamcrestTest{
    @Test
    public void testMethod(){
    	ArrayList<Object> myList = new ArrayList<Object>();
        assertThat(myList, is(empty()));
    }
}

Hamcrest

  1. allOf
    조건에 사용된 matcher가 모두 통과되는지에 대한 테스트
  2. anyOf
    조건에 사용된 matcher 중 하나만이라도 통과되는지에 대한 테스트
  3. not
    조건에 사용된 matcher의 결과와 맞니 않는지에 대한 테스트
  4. equalTo
    예상값과 matcher결과 이후 동일할 경우 성공
  5. is
    equalTo와 동일하나 가독성 증진을 위해 사용
  6. hasToString
    문자열이 포함되어 있는지에 대한 테스트
  7. instanceOf, isCompatibleType
    타입에 대한 테스트
  8. notNullValue, nullValue
    null값에 대한 테스트
  9. sameInstance
    두 Object가 같은지에 대한 테스트
  10. hasEntry, hasKey, hasValue
    Map 요소에 대해 포함 여부를 테스트
  11. hasItem, hasItems
    collection에 item포함 여부를 테스트
  12. hasItemInArray
    배열에 해당 item이 존재하는 지에 대한 테스트
  13. closeTo
    부동소수점 값에 대한 허용 근사치내 해당하는지에 대한 테스트
  14. greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo
    수치값의 크기에 따른 비교조건에 적합한 지에 대한 테스트(>, >=, <, <=)
  15. equalToIgnoringCase
    대소문자가 달라도 같은 것으로 판단하여 비교
  16. equalToIgnoringWhiteSpace
    공백을 제거한 상태에서 두 ㄱ밧이 같은지 비교
  17. containsString, endsWIth, startsWith
    문자열의 일부, 시작, 끝나는 부분에 대한 비교

Mock

Test Double이란?

대역 배우(Stunt double)를 일컫는 단어에서 차용한 것으로 테스트의 의존성을 독립시킬 수 있도록 지원하는 대역 객체들을 지칭

Test Double 사용시 장점

  • 테스트 대상 코드 격리
  • 테스트 속도 개선
  • 예측 불가능한 실행 요소 제거
  • 특수한 상황 테스트 가능
  • 감춰진 정보를 확인 가능

Mock-up이란?

  • 비행기, 자동차 등의 개발 단계에서 각 부의 배치를 보다 실제적으로 검토하기 위해서 제작되는 실물 크기의 모형.
  • 프로토타입, 시제품, 견본품

Mock-up Test란

Mock 객체를 만들어 테스트를 진행

Mock을 왜 사용할까요?

  • 테스트 코드가 다른 코드와의 의존 관계에 있어 오류가 나거나 테스트 진행이 안되는 경우
  • 네트워크나 데이터베이스 등 외부적인 요인에 영향을 받아 정상적으로 테스트 진행이 어려운 경우

Mockito

자바에서 단위테스트를 하기 위해 Mock을 만들어주는 프레임워크

Test Runner 지정 - @RunWith

테스트 환경의 기능 확장이나 초기화를 위해 사용된다. Sring에서 좀 더 유연한 테스트를 위해서는 @RunWith(SpringJUnit4ClassRunner.class)를 사용한다.

Mock 객체 만들기 - mock()

@Test
public void studentMockTest(){
	Student student = mock(Student.class);
    assertTrue(student != null);
}

Mock Annotation

  1. @Mock
@Mock
Student student;

@Test
public void studentMockTest(){
    MockitoAnnotations.initMocks(this);
    assertTrue(student != null);
}
  1. when(), then()
    해당 Mock 객체가 호출되거나 사용될 때 원하는 값을 리턴하여 테스트를 진행
@Test
public void testStudentMockWhenTest(){
    Student student = mock(Student.class);
    when(student.getName()).thenReturn("카이사");
    assertTrue("카이사".equals(student.getName()));
}
  1. doThrow()
@Test(expected = IllegalArgumentException.class)
public void testStudentDoThrow(){
    Student student = mock(Student.class);
    doThrow(new IllegalArgumentException()).when(p).setName(eq("홍길동"));
    p.setName(name);
}
  1. doNothing()
@Mock
StudentService studentService;

@Test
public void testDoNothing(){
    doNothing().when(studentService).getName(any());
    studentService.getName(“르블랑");
}
  1. @InjectMocks
    테스트 대상이 다른 객체를 포함할 때
public class StudentService {
    private Student student;
    public void addStudent(){
    }
}

@Mock
Student student

@InjectMocks
StudentService studentService

@Test
public void testStudentServiceInjectMock(){
    Student student = studentService.getStudent("애쉬");
    AssertTrue(student.getPosition() == "바텀");
}

Mock 호출 검증 - verify()

  • 해당 구문이 호출되었는지를 검증
@Test
public void testStudentMockVerify(){
    Student student = mock(Student.class);
    student.setName("이즈리얼");
    verify(student).setName("이즈리얼");
}
  • 호출 횟수 검증
@Test
 public void testStudentMockVerifyWithTimes(){
 ...
     verify(student, times(1)).size(); //일반 verify와 같습니다. 1번 실행되었는지 확인
     verify(student, atLeastOnce()).size(); // 최소 한 번 이상만 실행되면 OK
     verify(student, atMost(2)).size(); // 최대 두번까지 실행되면 OK
     verify(student, atLeast(3)).size(); // 최소 세 번은 실행되야 OK
     verify(student, never()).clear(); // 절대 호출되면 안됨
     verify(student, timeout(100).atLeast(1)).setName(any(String.class)); //100ms 시간 내에 한 번이상 실행되면 OK, setName에 오는 string은 아무거나 OK
}

Given, When, Then Pattern

BDD 기반으로 테스트하는 방법을 의미하며, 다음 예제와 같은 형식을 갖는다.

@Test
public void testPhoneBookInsertWhenIsEmpty(){
    given(phoneBookRepository.contains(momContactName))
    .willReturn(false);
    phoneBookService.register(momContactName, momPhoneNumber);
    then(phoneBookRepository).should().insert(momContactName, momPhoneNumber);
}

TDD

TDD - Test Driven Development

  • 매우 짧은 개발 써클의 반복 프로세스에 의존하는 방식으로, 테스트 코드를 먼저 만들고 테스트가 총과되는 코드를 만드는 개발 방법
  • Red, Green, Blue Circle
  • 장점
    • 깨끗한 코드
    • 유지보수 비용 절감
    • 결함 감소
  • 단점
    • 개발 시간의 증가
    • 테스트 코드 작성이 어려운 경우 배보다 배꼽이 더 크다.
    • 기존 개발 방법에 익숙한 경우 적응이 어렵다.

0개의 댓글