MVNO패키지 개발 Wiki

 

단위테스트 With JUnit

Page history last edited by fullbox 2 yrs ago
  • '실용주의 프로그래머를 위한 단위테스트 with JUnit' 책의 요약본입니다. 조금씩 마무리하겠습니다.

 

단위테스트 with JUnit

 

  • 테스트 주도 개발(TDD, Test Driven Development) 전략에서 필요한 프로그램의 테스트를 위한 구체적인 방법을 제시하고 있는 책으로써 개발하면서 발생하는 버그 및 에러들을 잡기 위한 최소한의 수고를 필요로 하며 매번 프로그램 개발, 수정 및 개선 후에 효율적인 단위테스트를 수행 및 자동화하기 위한 구체적이고도 자세한 전략을 기술하고 있습니다.

 


 

개요

 

단위테스트란?

 

- 테스트 대상이 되는 코드 기능의 아주 작은 특정 영역을 실행해보는, 개발자가 작성한 코드 조각

- 부분적인 테스트 검증으로 전체 테스트 시 각 부분 검증의 확신을 가질 수 있음

- 전체 테스트 시 디버깅 시 빠른 오류 추적이 가능

- 특정 소스 수정으로 인한 부수적인 피해(수정으로 인한 시스템 다른 부분에 피해를 만들어 내는 것)를 줄임

 

 

 

테스트 코드 작업 작성 요령

 

- 테스트에 필요한 모든 조건과 상황을 준비 설정(필요한 객체 새성, 필요한 자원 할당)

- 테스트 대상이 되는 메소드 호출

- 테스트 대상이 되는 메소드가 원하는 대로 동작한다는 것을 검증

- 실행 완료 후 다른 코드에 영향이 없게 정리 작업

 

 

 

assert method 사용 시 특이사항 및 유의점

 

  • assertEquals()

 

- assertEquals(String message, expected, actual, tolerance);

- 배열형을 위한 equals()메소드는 배열의 내용을 비교하는 것이 아니라 배열 reference 자체만 비교하므로 유의함

- 실수형 assertEquals() 사용 시 오차 한계(tolerance)를 지정하여야 함

- assertEquals("Should be 3 1/3", 3.33, 10.0/3.0, 0.01);

 

  • assertNull()

 

- assertNull(String metssage, Object obj);

- assertNotNull(String metssage, Object obj);

- 객체의 null여부 확인

 

  • assertSame()

 

- assertSame(String metssage, expected, actual);

- assertNotSame(String metssage, expected, actual);

- expected와 actual이 같은 객체를 참조하는지 판정

 

  • assertTrue()

 

- assertTrue(String message, boolean condition);

- assertFalse(String message, boolean condition);

- 제어흐름이 반드시 여기를 지나야함, 분기나 예외처리 검증, 하지만 절대 수행되지 않는다 하더라도 에러가 발생하는 것은 아님

 

  • fail()

 

- fail(String message);

- 테스트를 바로 실패 처리, 절대 수행되지 않아야 될 부분을 표시하는 데 사용(예외가 발생되는 부분 다음라인)

 

 

 

JUnit framework의 테스트 코드의 구조

 

  • import 필요, junit.framework.*;
  • TestCase 클래스 상속
  • String type contstructor 요구, super클래스의 constructor를 호출
  • 각 메소드는 test....() 형태로 정의

 

 

 

JUnit 테스트 조합 - TestSuite 클래스의 이용

 

  • 짧은 수행시간을 가진 test 메소드만 수행

 

public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new TestClassTwo("testShortTest"));
suite.addTest(new TestClassTwo("testAnotherShortTest");
return suite;
}

 

  • 테스트 클래스의 조합

 

import junit.framework.*;
public class TestClassComposite extends TestCase {
public TestClassComponsite(String method) {
super(method);
}
public static Test suite() {
TestSuite suite = new TestSuite();
// 모든 테스트 수행을 위해 suite 에 추가
suite.addTestSuite(TestClassOne.class);
// 테스트 클래스에 구현된 suite 메소드 이동
suite.addTest(TestClassTwo.suite());
return suite;
}
}

 

 

테스트별 준비 설정과 정리

 

  • 각 테스트들은 독립적으로 수행되어야 함
  • setUp(), tearDown() 메소드를 이용

 

oneTimeSetUp()
setUp()             -> 1
testMethod1()
tearDown()          -> 2
setUp()             -> 3
testMethod2()
tearDown()          -> 4
oneTimeTearDown()

 

  • oneTimeSetUp(), oneTimeTearDown() : 한번만 실행되는, suite를 시작할때의 준비 설정코드와 끝날 때의 정리코드
  • setUp(), tearDown() : 메소드별로 테스트 메소드 이전에 실행되는 준비 설정코드와 이후에 실행되는 정리코드

 

 

 

suite 별 준비 설정과 정리

 

  • 전체 테스트 suite 를 실행하고 난 다음에 설정하거나 정리해야 될 때 TestSetup 필요

 

public class TestClassTwo extends TestCase {
....
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new TestClassTwo("testShortTest"));
suite.addTest(new TestClassTwo("testAnotherShortTest"));
// TestSetup 생성
TestSetup wrapper = new TestSetup(suite) {
protected void setUp() {
oneTimeSetUp();
}
protected void tearDown() {
oneTimeTearDown();
}
};
return wrapper;
}
public static void oneTimeSetUp() {
// 한번만 실행되는 초기화 코드 작성
}
public static void oneTimeTearDown() {
// 한번만 실행되는 정리 코드 작성
}
}

 

 

JUnit 사용자 정의 assert 메소드

 

  • 지원하지 않는 assert메소드의 구현 및 특별한 데이터형을 조작해야 할 때 TestCase 의 하위 클래스에 구현하고모든 테스트 클래스는 해당 클래스를 상속해서 사용(프로젝트에 특성화된 기본 테스트 클래스를 만듬)

 

 

 

JUnit과 예외

 

예외 발생 유형과 테스트 작성 방법

  • 테스트에서 발생하는 예상된 예외

 

public void testForException() {
try {
sortMyList(null);
fail("Should have thrown an exception");
} catch(RuntimeException e) {
assertTrue(true);
}
}

 

 

예상하지 못한 예외

 

public void testData1() throws FileNotFoundException {
FileInputStream in = new FileInputStream("data.txt");
.....
}

 

 

테스트 메소드명 짓기

  • test 로 시작되는 메소드는 자동으로 테스트메소드로 인식되어 실행되므로 미뤄놓은 메소드들은 pendingTest...() 이런식으로 작성하여 테스트 수행치 않도록 하며 추후 검색 시 'pendingTest' 로 검색 가능

 

 

 

무엇을 테스트해야 하는가

 

Right - BICEP

 

Right

 

  • 결과가 옳은가?
  • 결과의 유효성 검사

 

Boundary

 

  • 모든 경계조건이 correct한가?
  • 대부분의 버그가 '경계'에 서식함
  • 다음 예를 참조하여 경계조건을 파악함

 

- 완전히 엉터리나 일관성 없는 값

- 잘못 형식화된 데이터, 이메일 주소 등.

- 아예 없거나 빠뜨린 값, 0, 0.0, "", null

- 합리적인 예상치에서 한참 떨어진 값, 사람의 나이가 10,000살

- 중복된 값이 있으면 안되는 목록에서 중복된 값

- 순서가 매겨져야 하는 목록에서 순서대로 되어 있지 않는 경우, 정렬 알고리즘에 정렫된 목록을 넘겨주는 경우

- 잘못된 순서나 기대한 순서와 다르게 일어나는 일

 

Inverse

 

  • 역 관계를 확인할 수 있는가?
  • 데이터가 데이터베이스에 잘 들어갔는지 확인할 때 그것을 데이터베이스에서 찾아보면 되는 방식
  • 원래 루틴과 역 루틴의 공통 에러로 감춰진 버그에 주의함
  • 역테스트 시 별도의 소스를 이용

 

Cross check

 

  • 다른 수단을 사용해서 결과를 교차 확인할 수 있는가?
  • 결과를 교차확인하기 위해 다른 알고리즘을 사용
  • 어떤 일을 수행하기 위한 알려진 방법이 있는데, 제품 코드에 사용하기에는 지나치게 느리거나 유연성이 없는 경우에 유용함
  • 분리된 데이터의 결과를 서로 교차 확인하는 데 사용(빌려간 책의 권수와 서가에 있는 책의 권수의 합은 전체 권수와 같아야 함

 

Error condition

 

  • 에러조건을 강제로 만들어 낼 수 있는가?

 

Performance

 

  • 성능 특성이 한도 내에 있는가?
  • 성능 그 자체가 아니라 입력 양이 많아지고, 문제가 복잡해지면서 성능이 변하는 경향을 말함
  • 개별적인 테스트 타이밍 조절, 과부하 조건의 시뮬레이션 등을 좀 더 잘 지원해주는 테스트 장식자를 사용(JUnitPerf)

 

 

 

CORRECT 경계 조건

경계조건에 대한 정리

 

- 형식 일치(Conformance) - 값의 형식이 기대한 형식과 일치하는가?

- 순서(Ordering) - 적절한 순서대로 되어 있거나 그렇지 않는 값인가?

- 범위(Range) - 적당한 최소값과 최대값 사이에 있는 값인가?

- 참조(Reference) - 코드가 외부 코드를 참조하는가?

- 존재성(Existence) - 값이 존재하는가?

- 개체 수(Cardinality) - 확실히 충분한 값이 존재하는가?

- 시간(Time) - 모든 것이 순서대로 일어나는가?제시간에?때맞추어?

 

  • 테스트 종료 후 '그 밖에 어떤 것이 잘못될 수 있는가?'라는 질문을 항상 가짐

 

C O R R E C T

COnformance - 형식 일치

 

- 이메일, 전화 번호, 계좌 번호, 파일 이름 같이 형식화 된 문자열 데이터 검사

- 구조가 더 복잡한 데이터 : 기대한 형식과 일치하는 지 확인

 

Ordering - 순서

 

- 레스토랑 주문을 담은 데이터 집합 객체를 받는 메서드 : 에피타이저 > 셀러드 > 주요리 > 디저트

- 항목들이 정상적인 순서로 되어 있는지 검증하는 테스트

 

Range - 범위

 

- 사람의 나이 : 200,000 살은 될 수 없음

- 각도 : 360도 이상은 될 수 없음

- 객체의 생성 시점에 범위를 검사하여 생성을 제한함으로써 적절한 범위의 값을 가진 객체를 생성하여 사용한다는 확신을 가짐

- 스택 및 리스트처럼 물리적인 데이터 구조에 따라 제한되는 범위를 테스트

- 스택의 경우 빈 스택이나 스택 오버플로우를 확인하는 부분을 검증

 

Reference - 참조

 

- 스택의 pop() 메소드는 비어있지 않는 스택을 필요로 함

- 자동차의 변속기를 운전상태에서 주차 상태로 바꾸려면 먼저 그차가 멈춰야 할 것임(변속기의 상태가 자동차의 상태에 달렸는지 확인)

- 객체의 사전조건과 사후조건에 대한 확인

 

Existence - 존재성

 

- '주어진 것이 존재하는가?'

- 파라미터 값이 null or 0 or "" 에 대한 검증

 

Cardinality - 개체 수

 

- '하나 차이에 의한 오류'

- 메소드가 개수를 잘 세는지, 어떤 대상을 얼마나 많이 가질 수 있는지 검증

- 0 일때, 1 일떄, 1 보다 클 때에 대한 검증 : '0-1-n 규칙'

- 1개 이상을 처리할 수 있다면 10,20, 1000개까지도 처리할 수 있을 것이라는 가정을 기반으로 함

- '0-1-n 규칙' 에서 n 은 항상 변수로 분리하여 가변적으로 바꿀 수 있도록 작성

 

Time - 시간

 

- 상대 시간(시간적 순서), 절대 시간(경과한 총 계산 시간), 동시성 문제(Concurrency)

- 메소드의 호출 순서에 대한 검증

- 제한시간(timeout) 내에 수행가능한지 테스트

- 동시성 문제 : 다중 스레드 프로그램에서 나타나는 병행성 문제 해결을 위한 테스트

- 스레드를 여러 개 생성하여 테스트 수행

 

모의 객체 사용하기

 

 

 

좋은 테스트의 특징

A-TRIP

 

- 자동적(Automatic)

- 철저함(Thorough)

- 반복 가능(Repeartable)

- 독립적(Independent)

- 전문적(Professional)

 

일관성있는 회귀테스트

  • 새로운 모듈이 시스템에 통합되거나 추가될 때마다 추가된 기능 부분을 테스트하면서 그 이전에 있던 기능 부분들도 다시 테스트하는 것

Comments (0)

You don't have permission to comment on this page.