SlideShare a Scribd company logo
1 of 71
Download to read offline
TDD/JUnit 조금더 알기
TDD/JUnit 파헤치기
myrisinsun@gmail.com
시작하기전에..
• Effective Unit Testing <2013, 한빛미디어>
• 옮긴이의 말

Effective 로 시작하는 책 대부분은 유행이 아닌

비교적 오랫동안 가치를 인정받는 듬직함을 보여줌.
• 단순한 따라하기, 기교 중심의 어떻게(How)? 가 아닌

주제에 관한 깊은 이해와 오랜 경험으로부터 우러나온

왜(Why)? 를 보여준다!
Agile, XP 그리고 TDD
얘들은 왜 뭉쳐 다닐까?
Agile?
• 나는 그냥 개념이야. 컨셉같은거?
• Less Document-Oriented.
• 계획을 통해 주도해가던 과거의 방법이 아닌.
• Code-Oriented.
• 일정한 주기로 동작하는 코드를 만들어 가는 반복 과정.
XP?
• 1999년 Kent Beck의 저서에서 사용

(Extreme Programming Explained)
• 고객이 원하는 양질의 소프트웨어를 빠른 시간안에 전달
을 목표
• XP가 제시하는 실천방법에는 TDD, Pair Programming
등..
복잡해.. 한줄로 요약을 해보면?
TDD는..
Agile 원칙을 지키는 방법론중의 하나인

XP가 제시하는 실천방법 중 하나!!
음.. 그래서 TDD는 어떻게 하는건가?


코딩 -> 테스트 -> 리팩토링
을 아래의 순서로 진행
테스트 -> 코딩 -> 리팩토링
TDD 간단 순서
요구사항: JukeBox 에 노래제목(Title)으로 가수명(Artist)을 찾는 기능 추가
1. test 를 먼저 작성
public void testGetArtistNameByTitleName() {
JukeBox jukeBox = new JukeBox();
String titleName = “Becuase of You”;
String artistName = jukeBox.getArtistNameByTitleName( titleName );
assertTrue(“Kelly Clarkson”.equals(artistName));
}
2. JukeBox.class 를 구현
위의 Test 를 통과할 수 있는 수준으로만 코드를 구현하는것이 포인트.
앞으로 필요할것 같은? 코드를 임의로 구현하지 않음.
그렇다면 TDD로 얻을 수 있는게
뭐지?
• 정확한 사용 시나리오가 포함된

자동화된 실행 가능한 코드
• 군더더기 없는 제품 코드.
그렇다면 JUnit은 ?
‘테스트’ 자체가 중요시 되면서

편의성과 자동화된 테스트 환경을 제공해주기 위한

프레임워크
JUnit은 Reflection을 사용
• Java Reflection API(java.lang.reflect)는

클래스, 필드, 메소드를 들여다 볼 수 있는 도구.
• JVM에서 실행되는 자바 프로그램의 내부 구성을 확인하
거나 런타임시에 프로그램의 작동방법을 변경하고자 하
는 경우에 사용.
• 예를들면.. JUnit은 @BeforeClass, @Before 등의 메소
드를 검색하고 실행하는데 활용.
Java Reflection 예제
public class MyReflection {
public static void main(String args[])
{
try {
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
좋은 테스트란?
• 읽기 쉬운 테스트 코드

-소스코드와 같은 수준의 가독성 유지
• 구조를 잘 갖춘 테스트

-통짜 클래스가 아닌 적정한 수준의 구성 (화면 스크롤 제약..)
• 엉뚱한 걸 검사하지 말자

-테스트 메소드명은 중요
• 테스트가 얼마나 독립적인가?

-방금 개봉한 새PC에 버전 관리 서버에서 내려받은 테스트 코드를 바로 실행
• 믿고 쓰는 테스트 및 결과

-경계값으로 만들어진 테스트들

-하지만 assert가 없는 테스트라면?
테스트 더블?
• 특별한 목적으로 테스트 전용 장치를 만들어 사용.
• 이때 여러 종류의 테스트 장치(객체)를 통칭하는 용어.
• 쉽게..

테스트 하는데 필요한 객체 대신

의도적으로 변형시킨 다른 객체로 대체하여 사용하는것.
테스트 전용 장치의 필요성?
• 테스트 대상 코드를 격리한다
• 테스트 속도를 개선한다.
• 예측 불가능한 실행 요소를 제거한다.
• 특수한 상황을 시뮬레이션한다.
• 감춰진 정보를 얻어낸다.
테스트 대상 코드를 격리한다.
• 테스트 기준에서 코드는 2가지로 분류 가능



테스트 대상코드

-Car



테스트 대상코드와 상호작용하는 코드

-Engine, Route



public class Car {

private Engine engine;

private Route route;

private Audio audio;
테스트 속도를 개선한다.
• 실시간 교통정보를 반영하여 경로를 지도상에 출력
• 경로를 탐색하는 메소드가 아닌

계산된 경로를 화면에 출력하는 메소드의 테스트는?
• 굳이 계산할 필요 없이

미리 계산해둔 값을 반환하도록 하여 시간을 절약
예측 불가능한 실행 요소를 제거한다.
• 결과에 영향을 주는 모든 요소를 결정적으로 만든다.
• 예를들면

현재의 시간을 기준으로 동작되는 로직에는

항상 일정한 시간을 리턴하는 테스트 더블을 사용
특수한 상황을 시뮬레이션 한다.
• 실행도중 네트워크가 끊어지는 상황의 재현, 테스트.
• 테스트 실행중에 Lan선을 잠시 뽑을까?
• throw new java.net.ConnectException("Connection
timed out")
감춰진 정보를 얻어낸다.
• 테스트 대상의 멤버변수가 private이면서

외부에서 값의 확인이 필요할때.
• 테스트 대상을 상속, 구현할때 필요한

getter메소드를 추가하여 테스트 더블을 생성
테스트 더블의 종류
• 테스트 스텁

최소한의 형태만 가지는 가짜.
• 가짜 객체

최소한의 로직을 가지는 가짜.
• 테스트 스파이

추가 정보나 임의의 로직을 기존 객체를 변형하여 구현
• Mock객체

특정조건과 그에 대한 행동을 정의하여 구현
테스트 스텁
public void log(LogLevel level, String message) {
//아무일도 하지 않아요~
}
public LogLevel getLogLevel() {
// 스텁은 아무일도 하지 않아요~
return LogLevel.WARN;
}
가짜 객체
진짜 객체인 척? 뭔가를 하지만, 결국은 딴짓을 하는 객체


public class fake.... {
private Collection<User>users = new ArrayList<User>();
public void save(User user) {
//실제로는 DB로 저장을 해야하지만..
users.add(user);
}
public User findByName(String username) {
//실제로는 DB에서 쿼리로 읽어와야 하지만..
for (User user : users) {
if (user.getUsername().equals(username)) {
return user;
}
}
}
}
테스트 스파이
public interface DLogTarget {
void write(Level level, String message);
}
public class SpyTarget implements DLogTarget {
@Override
public void write(Level level, String message);
boolean received(level level, String message) {
//필요한 정보를 물어보고 확인할 수 있다.
}
}
Mock 객체
Map<String, String> testMock = mock(Map.class);
when( testMock.get("best1") ).thenReturn("Taylor Swift");
when( testMock.get("best2") ).thenReturn("Kelly Clarkson");
when( testMock.get("best3") ).thenReturn("Marie Digby");
System.out.println( testMock.get("best1") );
System.out.println( testMock.get("best2") );
System.out.println( testMock.get("best3") );
Test 코딩의 3단법? 3단구조?
준비-시작-단언 의 3단계로 구현
준비
MP3Tag mp3Tag = new MP3Tag();
ID3v2 id3v2 = null;
시작
mp3Tag.loadFile(filepath);
id3v2 = mp3Tag.getTagID3v2();
단언
assertEquals("Kelly clarkson", ID3v2.getArtist());
Code Smell ?
• Code Smell 이란 코드의 버그나 기술적인 문제를 뜻하지 않음.

개발 속도를 저해하거나 추후 버그나 장애를 일으킬만한

나쁜 코드 디자인을 뜻한다.
• Kent Beck이 최초로 사용했고, 이후 Martin Folwer의 책에 언
급되며 많이 쓰이는 용어.

(Refactoring: Improving the Design of Existing Code.)
• 나쁜 코드의 냄새를 3가지 유형으로 나누어 살펴봄

가독성

유지보수성

신뢰성
가독성

Readability
가독성#1 기본 타입 단언
의미를 알 수 없는 단어나 숫자가 단언하려는 의도를 가리고 있음.
String out = grep.grep("match", "test.txt", content);
assertTrue(out.indexOf("test.txt:1 1st match") != -1);
-> 개선방법#1
assertTrue(out.contains('test.txt:1 1st match"));
-> 개선방법#2
assertThat(out.contains("test.txt:1 1st match"), equals(true));
-> 개선방법#3
assertThat(out, containsString("text.txt:1 1st match"));
가독성#2 광역 단언
• 너무 작은 부분까지 단언하려는 집착으로

하나만 잘못되어도 바로 실패.

의도했던 핵심 단언이 나머지 단언에 묻힘.
• 로그파일에 대한 검증

광대한 로그파일. 사소한 부분의 변화에도 실패
• assertEquals(expectedOutput, output.content());
가독성#3 비트 단언
• assertTrue(Platform.IS_32_BIT ^ Platform.IS_64_BIT);
• 비트 연산에 익숙한 프로그래머는 많지 않다.
가독성#4 부차적 상세정보
• 읽기 쉬운 코드는 읽는 이에게 그 의도와 목적, 의미를 빠
르게 보여준다.
• 그리고 프로그래머는 코드를 훑을 때 본질이 무엇인가를
찾을 뿐, 자잘한 내용은 크게 신경 쓰지 않음.
• 테스트 코드에 부수적인 정보가 넘쳐나 본질이 숨으면?
• 테스트 의도를 파악하기 위해 코드를 빙빙~ 돌아야하면?
가독성#4 부차적 상세정보
• 핵심이 아닌 설정은 private 메서드나 셋업 메서드로 추
출
• 적절한 인자와 서술형 이름을 사용하라
• 한 메서드 안에서는 모두 같은 수준으로 추상화하라
가독성#5 다중인격
• 하나의 몸(메소드)에 여러개의 영혼(단언).

테스트 개선 방법중 가장 쉬운 방법.
• 하나의 테스트는 오직 한 가지만 똑바로 검색해야 한다.

(테스트 당 단언문이 하나를 뜻하는 것은 아님)
• test메소드에 객체를 생성하고 테스트 코드를 작성할때

객체를 생성한 김에 다른 단언문도 몇개 추가해볼까?
가독성#6 쪼개진 논리
• 긴 코드가 나타나면 '흩어진 코드'를

찾아 스크롤을 해야한다.
• 로직을 찾아서.. 데이터 처리과정을 찾아서~

이리저리 해메지 않도록
• 외부 데이터와 코드를 모두 테스트 안으로 옮기자!
• ex) 첫번째 테스트는 변수 할당을 다루고

두번째 테스트는 메서드 호출을 다루자
• 예제는 다음장에..
가독성#6 쪼개진 논리
다음과 같은 명령어가 포함된 쉘을 자바에서 실행 후
테스트를 진행한다면.
sed -i “s/이스빈다/있습니다/g” welcome.txt
테스트 소스뿐만 아니라 쉘 파일까지 모두 검토 해야함.
Eclipse IDE툴이 편리하다고는 하지만...
잠깐. 데이터와 로직의 분리기준
• 짧다면 통합하라
• 통합하기에 너무 길다면 

팩토리 메서드나 테스트 데이터 생성기로 분리
• 이것도 쉽지 않다면 독립 파일로 남겨둬라
가독성#7 매직넘버
대부분의 프로그래머가 동의하는
매직넘버를 피하자
game.roll(10, 12);
assertThat(game.score(), is(equalTo(300)));
-> 개선방법#1
roll( pins(10), times(12));
-> 개선방법#2
roll(TEN_PINS, TWELVE_TIMES);
가독성#8 셋업 설교
• 셋업 메서드가 길고, 복잡하고 지루하다면?
• 참고할만한 방법 3가지

-셋업에서 핵심을 제외한 정보는 private 메소드로 추출

-알맞은 서술적 이름을 사용

-셋업 내의 추상화 수준을 통일
• 샘플코드는 다음장에…
가독성#8 셋업 설교
셋업 설교는 짧은 테스트를 위한 너무 긴 준비작업을 뜻한다.
@Before
public void setUp() throws Exception {
String tempDir = System.getProperty("java.io.tmpdir");
tempDir = new File(tempDir, "2014");
tempDir.mkdir();
String fileSeparator = System.propertiesSystem("file.separator");
List<String> listWorkFiles = new ArrayList<String>();
listWorkFiles.add( ..... fileSeparator ....... );
listWorkFiles.add( ..... fileSeparator ....... );
listWorkFiles.add( ..... fileSeparator ....... );
..기타 등등 코드...
가독성#8 셋업 설교
세부 정보를 추출하여 한결 명확해진 셋업의 모습
@Before
public void setUp() throws Exception {
tempDir = createTempDir("2014");
listWorkFiles = createWorkFileList();
..
..
}
가독성#9 과잉보호 테스트
진짜 단언문 앞에 불필요한 단언문이 있는경우.
Data data = project.getData();
assertNotNull(data);
assertEquals(4, data.count());
유지보수성

Maintainability
유지보수성#1 중복
상수 중복 그리고 메소드 중복
@Test
public void emptyTemplate() throws Exception {
assertEquals("", new Template("").evaluate());
}
@Test
public void plainTextTemplate() throws Exception {
assertEquals("plaintext", new Template("plaintext").evaluate());
}
유지보수성#1 중복
1차 상수 중복 개선 (2차는 메소드 중복 개선)
@Test
public void emptyTemplate() throws Exception {
String template = "";
assertEquals(template, new Template(template).evaluate());
}
@Test
public void plainTextTemplate() throws Exception {
String template = "plaintext";
assertEquals(template, new Template(template).evaluate());
}
유지보수성#2 조건부 로직
• 테스트중에 실패가 확인되었다.
• 어디서 실패가 나온건가?
• 조건부 로직이 이를 방애한다.
유지보수성#2 조건부 로직
유지 보수를 어렵게 하는 테스트 코드 속의 조건부 로직
public void returnAnIteratorForContents() throws Exception {
Dictionary dict = new Dictionary();
dict.add("A", new Long(3));
dict.add("B", "21");
for (Iterator e = dict.iterator(); e.hasNext();) {
Map.Entry entry = (Map.Entry) e.next();
if ("A".equals(entry.getKey())) {
assertEquals(3L, entry.getValue());
}
if ("B".equals(entry.getKey())) {
assertEquals("21", entry.getValue());
}
}
}
유지보수성#2 조건부 로직
@Test
public void returnAnIteratorForcontents() throws Exception {
Dictionary dict = new Dictionary();
dict.add("A", new Long(3));
dict.add("B", "21");
assertContains(dict.iterator(), "A", 3L);
assertContains(dict.iterator(), "B", "21");
}
private void assertContain(Iterator i, Object key, Object value) {
while (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
if (key.equals(entry.getKey()) {
assertEquals(value, entry.getValue());
return;
}
}
fail("Iterator didn't contain " + key + " => " + value);
}
유지보수성#3 양치기 테스트
• 간헐적으로 실패하는 테스트.
• 날짜, 시간에 따라 동작이 다르거나

입출력, CPU 부하, 네트워크에 따라 다른 결과
유지보수성#4 파손된 파일 경로
테스트를 순식간에 망가뜨릴 수 있는 절대 경로
new File(“C:workspacecatalog.xml”);
-> 개선방법#1
new File("/workspace/catalog.xml");
-> 개선방법#2
new File(“./src/test/data/catalog.xml");
유지보수성#5 끈질긴 임시 파일
• 가장 먼저.. 파일이 꼭 있어야 하는가?
• 테스트에 사용한 임시파일이

다음 테스트까지 남아 있다면?
• @Before 메서드에서 파일을 삭제하라

가능하면 임시 파일명도 유일하게 지어라
• File.createTempFile("catalog", ".xml", DirectoryPath);

JVM프로세스가 종료될 때에나 지워지기 때문에 비추천
유지보수성#6 잠자는 달팽이
• 메모리는 빠르지만

디스크, Network은 상대적으로 느리다
• 또한 Thread.sleep() 역시 느.리.다.
• 예제코드는 다음장에..
• Thread가 동작하는것에 대해

충분한 시간(sleep())을 준다는것은 비효율.
• java.util.concurrent패키지의

CountDownLatch() 활용
유지보수성#6 잠자는 달팽이
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
values.add(counter.getAndIncrement());
}
}
for (int i=0; i < 10; i++ ) {
new Thread(runnable).start();
}
Thread.sleep(500);
assertEquals(.., ..);
유지보수성#8 파라미터화된 혼란
• 파라미터화된 테스트 패턴 이란?

데이터를 아주 조금씩만 바꿔가며 수차례 반복적인 검사.
• 나쁜냄새가 나는 코드
• JUnit이 제공하는 방법
• 여러 단언문을 하나의 메서드로 합치는 방법
유지보수성#8 파라미터화된 혼란
@Test
public void testOne() {
assertEquals("I", format(1));
}
public void testTwo() {
assertEquals("II", format(2));
}
public void testThree() {
assertEquals("III", format(3));
}
public void testFour() {
assertEquals("IV", format(4));
}
유지보수성#8 파라미터화된 혼란
@RunWith(Parameterized.class)
public class RomanNumeralsTest {
private int number;
private String numeral;
public RomanNumeralsTest(int number, String numeral) {
this.number = number;
this.numeral = numeral;
}
@Parameters
public static Collection<Object[]> data() {
return asList(new Object[][] {
{ 1, "I" }, { 2, "II" }, { 3, "III" }, { 4, "IV" } }
}
@Test
public void formatsPositiveIntegers() {
assertEquals(numeral, format(number));
}
}
하지만 테스트 결과가 익명으로 보여짐.
유지보수성#8 파라미터화된 혼란
여러 단언문을 하나의 메서드로 합치기
public void formatsPositiveIntegers() {
assertEquals("I", format(1));
assertEquals("II", format(2));
assertEquals("IV", format(4));
assertEquals("V", format(5));
}
유지보수성#9 메서드간 응집력 결핍
• OOP 의 개념중

낮은 결합도, 높은 응집력
• 각각의 테스트 메소드가 일부 픽스처만 사용
• 픽스처(Fixture)란?

테스트를 수행하는데 필요한 정보나 객체들
• 예제코드는 다음장에..
유지보수성#9 메서드간 응집력 결핍
public class AccountTest {
Account account;
Rule rule1, rule2, rule3, rule4;
..
@Test
public void testCalcTax() {
List list = new Array....
...
create(rule1, 1500);
create(rule2, 80);
}
@Test
public void testCalcFee() {
List list = new Array....
...
create(rule3, 1500);
create(rule4, 80);
}
신뢰성
Trustworthiness
신뢰성#1 주석으로 변한 테스트
• 특정 테스트 메소드 전체가 주석이 되어 있다면?
• 주석처리한 이유를 찾기 위해 아까운

프로그래머의 시간을 좀먹게 한다.
• 안쓰는건지?

특수한 상황에서만 써야하는건지?

혼란스러워진다.
• 최고의 방법은 지워버리자!
신뢰성#2 오해를 낳는 주석
• 실제 동작과 다른 주석이 있다면?

이런 불일치를 그대로 믿고 진행한다면?
• 주석 대신 더 적절한 변수명/메서드명 사용
• 주석이 사용된 부분을 의미있는 메소드명으로 분리
유지보수성#3 절대 실패하지 않는 테스트
코드가 정상동작한다면 catch 블록이 예외를 잡아서 결과는 성공
코드가 비정상동작하여 예외가 발생하지 않으면 테스트 메서드는 정상
종료
@Test
public void includeForMssingResourceFails() {
try {
new Environment().include("없는 자원");
} catch (IOException e) {
assertThat(.e.getMessage(), contains("없는 자원"));
}
}
유지보수성#3 절대 실패하지 않는 테스트
개선 코드
public void includeForMssingResourceFails() {
try {
new Environment().include("없는 자원");
fail();
} catch (IOException e) {
assertThat(.e.getMessage(), contains("없는 자원"));
}
}
유지보수성#3 절대 실패하지 않는 테스트
더욱 좋은방법은
@Test 애너테이션에 expected 속성 사용
@Test(expected = IOException.class)
public void includeingMissingResourceFails() {
new Environment().include("실존하지 않는 자원");
}
신뢰성#4 지키지 못할 약속
• 아무 '일'도 안하는 테스트
• '무언가 일은 하지만, 정작 '검증'은 안하는 테스트
• 이름값 못하는 테스트
신뢰성#4 지키지 못할 약속
아무 '일'도 안하는 테스트
@Test
public void testFilteringObject() throws Exception {
//List list........
//String result = create(........
//...
//...
//assertThat(........, .......);
}
신뢰성#4 지키지 못할 약속
'무언가 일은 하지만, 정작 '검증'은 안하는 테스트
테스트 메소드에 단언문이 없다면?
Exception이 발생하지 않는 한 정상
신뢰성#4 지키지 못할 약속
이름값 못하는 테스트
@Test
public void zipBetweenTwoArraysProducesAHash() throws Exception
{
...
...
...
assertNotNull("We have a hash back", zipped.flatten();
}
신뢰성#5 낮아진 기대치
종종 게으르고 가장 쉬운 길로 가려는 경향.
쉬운 방법이 옳을 수도 있지만.. 정도가 심하다면?
double sample1 = calc1.cal();
double sample2 = calc2.cal();
assertThat(sample1, is(greaterThan(0.0)));
assertThat(sample2, is(greaterThan(0.0)));
assertTrue(sample1 != sample2);
신뢰성#6 플랫폼 편견
• JAVA가 제창하던

Write Once, Run Anywhere



하지만 실패..
• 플랫폼 편견이란 필요한 플랫폼을 모두

다루지 못하는 것.

More Related Content

What's hot

katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드SangIn Choung
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDDSunghyouk Bae
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트YongEun Choi
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례SangIn Choung
 
Introduce Katalon tool
Introduce Katalon toolIntroduce Katalon tool
Introduce Katalon tool재연 김
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례SangIn Choung
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
TDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringTDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringSuwon Chae
 
KGC2010 - 낡은 코드에 단위테스트 넣기
KGC2010 - 낡은 코드에 단위테스트 넣기KGC2010 - 낡은 코드에 단위테스트 넣기
KGC2010 - 낡은 코드에 단위테스트 넣기Ryan Park
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Testbeom kyun choi
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)Suwon Chae
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven DevelopmentChangHyeon Bae
 
Effective unit testing - 좋은테스트 요약
Effective unit testing - 좋은테스트 요약Effective unit testing - 좋은테스트 요약
Effective unit testing - 좋은테스트 요약YongEun Choi
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 SangIn Choung
 
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)SangIn Choung
 
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)SangIn Choung
 
구글테스트
구글테스트구글테스트
구글테스트진화 손
 

What's hot (18)

katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDD
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
Introduce Katalon tool
Introduce Katalon toolIntroduce Katalon tool
Introduce Katalon tool
 
C++과 TDD
C++과 TDDC++과 TDD
C++과 TDD
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
TDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringTDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: Refactoring
 
KGC2010 - 낡은 코드에 단위테스트 넣기
KGC2010 - 낡은 코드에 단위테스트 넣기KGC2010 - 낡은 코드에 단위테스트 넣기
KGC2010 - 낡은 코드에 단위테스트 넣기
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
Effective unit testing - 좋은테스트 요약
Effective unit testing - 좋은테스트 요약Effective unit testing - 좋은테스트 요약
Effective unit testing - 좋은테스트 요약
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
 
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)
(편집-테스트카페 발표자료) 1인 QA 수행사례로 발표한 자료 (W프로젝트 사례)
 
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)
사용자 스토리 대상 테스트 설계 사례(테스트기본교육 3장 3절)
 
구글테스트
구글테스트구글테스트
구글테스트
 

Viewers also liked

Spring-Boot (springcamp2014)
Spring-Boot (springcamp2014)Spring-Boot (springcamp2014)
Spring-Boot (springcamp2014)sung yong jung
 
소프트웨어 개발자 로드맵
소프트웨어 개발자 로드맵소프트웨어 개발자 로드맵
소프트웨어 개발자 로드맵중선 곽
 
자동화된 Test Case의 효과
자동화된 Test Case의 효과자동화된 Test Case의 효과
자동화된 Test Case의 효과도형 임
 
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례Jemin Huh
 
스프링 부트와 로깅
스프링 부트와 로깅스프링 부트와 로깅
스프링 부트와 로깅Keesun Baik
 

Viewers also liked (7)

Spring-Boot (springcamp2014)
Spring-Boot (springcamp2014)Spring-Boot (springcamp2014)
Spring-Boot (springcamp2014)
 
소프트웨어 개발자 로드맵
소프트웨어 개발자 로드맵소프트웨어 개발자 로드맵
소프트웨어 개발자 로드맵
 
자동화된 Test Case의 효과
자동화된 Test Case의 효과자동화된 Test Case의 효과
자동화된 Test Case의 효과
 
Maven의 이해
Maven의 이해Maven의 이해
Maven의 이해
 
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례
Spring boot 를 적용한 전사모니터링 시스템 backend 개발 사례
 
스프링 부트와 로깅
스프링 부트와 로깅스프링 부트와 로깅
스프링 부트와 로깅
 
Spring Boot 소개
Spring Boot 소개Spring Boot 소개
Spring Boot 소개
 

Similar to TDD.JUnit.조금더.알기

아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 aChoonghyun Yang
 
Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Daum DNA
 
Effective Unit Testing
Effective Unit TestingEffective Unit Testing
Effective Unit TestingYeon Soo Kim
 
클린 코드 part2
클린 코드 part2클린 코드 part2
클린 코드 part2Minseok Jang
 
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)DK Lee
 
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기Ahreum Kim
 
X unittestpattern 1장_아꿈사
X unittestpattern 1장_아꿈사X unittestpattern 1장_아꿈사
X unittestpattern 1장_아꿈사효원 강
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
Clean code chapter9
Clean code chapter9Clean code chapter9
Clean code chapter9ukjinkwoun
 
유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙Hyosang Hong
 
Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Hyosang Hong
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509영석 조
 
소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙Hong Hyo Sang
 
Tobi 스프링 2장 php version
Tobi 스프링 2장   php versionTobi 스프링 2장   php version
Tobi 스프링 2장 php versionukjinkwoun
 
프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들Lee Geonhee
 
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거Javajigi Jaesung
 

Similar to TDD.JUnit.조금더.알기 (20)

Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a
 
Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기
 
S66 goos-w7
S66 goos-w7S66 goos-w7
S66 goos-w7
 
Effective Unit Testing
Effective Unit TestingEffective Unit Testing
Effective Unit Testing
 
클린 코드 part2
클린 코드 part2클린 코드 part2
클린 코드 part2
 
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)
자바 웹 개발 시작하기 (8주차 : 명세서, 단위테스트, 통합)
 
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
 
Tdd
TddTdd
Tdd
 
X unittestpattern 1장_아꿈사
X unittestpattern 1장_아꿈사X unittestpattern 1장_아꿈사
X unittestpattern 1장_아꿈사
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
Clean code chapter9
Clean code chapter9Clean code chapter9
Clean code chapter9
 
유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙
 
Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙
 
Tdd
TddTdd
Tdd
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509
 
소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙
 
Tobi 스프링 2장 php version
Tobi 스프링 2장   php versionTobi 스프링 2장   php version
Tobi 스프링 2장 php version
 
프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들
 
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
 

TDD.JUnit.조금더.알기

  • 1. TDD/JUnit 조금더 알기 TDD/JUnit 파헤치기 myrisinsun@gmail.com
  • 2. 시작하기전에.. • Effective Unit Testing <2013, 한빛미디어> • 옮긴이의 말
 Effective 로 시작하는 책 대부분은 유행이 아닌
 비교적 오랫동안 가치를 인정받는 듬직함을 보여줌. • 단순한 따라하기, 기교 중심의 어떻게(How)? 가 아닌
 주제에 관한 깊은 이해와 오랜 경험으로부터 우러나온
 왜(Why)? 를 보여준다!
  • 3. Agile, XP 그리고 TDD 얘들은 왜 뭉쳐 다닐까?
  • 4. Agile? • 나는 그냥 개념이야. 컨셉같은거? • Less Document-Oriented. • 계획을 통해 주도해가던 과거의 방법이 아닌. • Code-Oriented. • 일정한 주기로 동작하는 코드를 만들어 가는 반복 과정.
  • 5. XP? • 1999년 Kent Beck의 저서에서 사용
 (Extreme Programming Explained) • 고객이 원하는 양질의 소프트웨어를 빠른 시간안에 전달 을 목표 • XP가 제시하는 실천방법에는 TDD, Pair Programming 등..
  • 6. 복잡해.. 한줄로 요약을 해보면? TDD는.. Agile 원칙을 지키는 방법론중의 하나인
 XP가 제시하는 실천방법 중 하나!!
  • 7. 음.. 그래서 TDD는 어떻게 하는건가? 
 코딩 -> 테스트 -> 리팩토링 을 아래의 순서로 진행 테스트 -> 코딩 -> 리팩토링
  • 8. TDD 간단 순서 요구사항: JukeBox 에 노래제목(Title)으로 가수명(Artist)을 찾는 기능 추가 1. test 를 먼저 작성 public void testGetArtistNameByTitleName() { JukeBox jukeBox = new JukeBox(); String titleName = “Becuase of You”; String artistName = jukeBox.getArtistNameByTitleName( titleName ); assertTrue(“Kelly Clarkson”.equals(artistName)); } 2. JukeBox.class 를 구현 위의 Test 를 통과할 수 있는 수준으로만 코드를 구현하는것이 포인트. 앞으로 필요할것 같은? 코드를 임의로 구현하지 않음.
  • 9. 그렇다면 TDD로 얻을 수 있는게 뭐지? • 정확한 사용 시나리오가 포함된
 자동화된 실행 가능한 코드 • 군더더기 없는 제품 코드.
  • 10. 그렇다면 JUnit은 ? ‘테스트’ 자체가 중요시 되면서
 편의성과 자동화된 테스트 환경을 제공해주기 위한
 프레임워크
  • 11. JUnit은 Reflection을 사용 • Java Reflection API(java.lang.reflect)는
 클래스, 필드, 메소드를 들여다 볼 수 있는 도구. • JVM에서 실행되는 자바 프로그램의 내부 구성을 확인하 거나 런타임시에 프로그램의 작동방법을 변경하고자 하 는 경우에 사용. • 예를들면.. JUnit은 @BeforeClass, @Before 등의 메소 드를 검색하고 실행하는데 활용.
  • 12. Java Reflection 예제 public class MyReflection { public static void main(String args[]) { try { Class c = Class.forName("java.lang.String"); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } }
  • 13. 좋은 테스트란? • 읽기 쉬운 테스트 코드
 -소스코드와 같은 수준의 가독성 유지 • 구조를 잘 갖춘 테스트
 -통짜 클래스가 아닌 적정한 수준의 구성 (화면 스크롤 제약..) • 엉뚱한 걸 검사하지 말자
 -테스트 메소드명은 중요 • 테스트가 얼마나 독립적인가?
 -방금 개봉한 새PC에 버전 관리 서버에서 내려받은 테스트 코드를 바로 실행 • 믿고 쓰는 테스트 및 결과
 -경계값으로 만들어진 테스트들
 -하지만 assert가 없는 테스트라면?
  • 14. 테스트 더블? • 특별한 목적으로 테스트 전용 장치를 만들어 사용. • 이때 여러 종류의 테스트 장치(객체)를 통칭하는 용어. • 쉽게..
 테스트 하는데 필요한 객체 대신
 의도적으로 변형시킨 다른 객체로 대체하여 사용하는것.
  • 15. 테스트 전용 장치의 필요성? • 테스트 대상 코드를 격리한다 • 테스트 속도를 개선한다. • 예측 불가능한 실행 요소를 제거한다. • 특수한 상황을 시뮬레이션한다. • 감춰진 정보를 얻어낸다.
  • 16. 테스트 대상 코드를 격리한다. • 테스트 기준에서 코드는 2가지로 분류 가능
 
 테스트 대상코드
 -Car
 
 테스트 대상코드와 상호작용하는 코드
 -Engine, Route
 
 public class Car {
 private Engine engine;
 private Route route;
 private Audio audio;
  • 17. 테스트 속도를 개선한다. • 실시간 교통정보를 반영하여 경로를 지도상에 출력 • 경로를 탐색하는 메소드가 아닌
 계산된 경로를 화면에 출력하는 메소드의 테스트는? • 굳이 계산할 필요 없이
 미리 계산해둔 값을 반환하도록 하여 시간을 절약
  • 18. 예측 불가능한 실행 요소를 제거한다. • 결과에 영향을 주는 모든 요소를 결정적으로 만든다. • 예를들면
 현재의 시간을 기준으로 동작되는 로직에는
 항상 일정한 시간을 리턴하는 테스트 더블을 사용
  • 19. 특수한 상황을 시뮬레이션 한다. • 실행도중 네트워크가 끊어지는 상황의 재현, 테스트. • 테스트 실행중에 Lan선을 잠시 뽑을까? • throw new java.net.ConnectException("Connection timed out")
  • 20. 감춰진 정보를 얻어낸다. • 테스트 대상의 멤버변수가 private이면서
 외부에서 값의 확인이 필요할때. • 테스트 대상을 상속, 구현할때 필요한
 getter메소드를 추가하여 테스트 더블을 생성
  • 21. 테스트 더블의 종류 • 테스트 스텁
 최소한의 형태만 가지는 가짜. • 가짜 객체
 최소한의 로직을 가지는 가짜. • 테스트 스파이
 추가 정보나 임의의 로직을 기존 객체를 변형하여 구현 • Mock객체
 특정조건과 그에 대한 행동을 정의하여 구현
  • 22. 테스트 스텁 public void log(LogLevel level, String message) { //아무일도 하지 않아요~ } public LogLevel getLogLevel() { // 스텁은 아무일도 하지 않아요~ return LogLevel.WARN; }
  • 23. 가짜 객체 진짜 객체인 척? 뭔가를 하지만, 결국은 딴짓을 하는 객체 
 public class fake.... { private Collection<User>users = new ArrayList<User>(); public void save(User user) { //실제로는 DB로 저장을 해야하지만.. users.add(user); } public User findByName(String username) { //실제로는 DB에서 쿼리로 읽어와야 하지만.. for (User user : users) { if (user.getUsername().equals(username)) { return user; } } } }
  • 24. 테스트 스파이 public interface DLogTarget { void write(Level level, String message); } public class SpyTarget implements DLogTarget { @Override public void write(Level level, String message); boolean received(level level, String message) { //필요한 정보를 물어보고 확인할 수 있다. } }
  • 25. Mock 객체 Map<String, String> testMock = mock(Map.class); when( testMock.get("best1") ).thenReturn("Taylor Swift"); when( testMock.get("best2") ).thenReturn("Kelly Clarkson"); when( testMock.get("best3") ).thenReturn("Marie Digby"); System.out.println( testMock.get("best1") ); System.out.println( testMock.get("best2") ); System.out.println( testMock.get("best3") );
  • 26. Test 코딩의 3단법? 3단구조? 준비-시작-단언 의 3단계로 구현 준비 MP3Tag mp3Tag = new MP3Tag(); ID3v2 id3v2 = null; 시작 mp3Tag.loadFile(filepath); id3v2 = mp3Tag.getTagID3v2(); 단언 assertEquals("Kelly clarkson", ID3v2.getArtist());
  • 27. Code Smell ? • Code Smell 이란 코드의 버그나 기술적인 문제를 뜻하지 않음.
 개발 속도를 저해하거나 추후 버그나 장애를 일으킬만한
 나쁜 코드 디자인을 뜻한다. • Kent Beck이 최초로 사용했고, 이후 Martin Folwer의 책에 언 급되며 많이 쓰이는 용어.
 (Refactoring: Improving the Design of Existing Code.) • 나쁜 코드의 냄새를 3가지 유형으로 나누어 살펴봄
 가독성
 유지보수성
 신뢰성
  • 29. 가독성#1 기본 타입 단언 의미를 알 수 없는 단어나 숫자가 단언하려는 의도를 가리고 있음. String out = grep.grep("match", "test.txt", content); assertTrue(out.indexOf("test.txt:1 1st match") != -1); -> 개선방법#1 assertTrue(out.contains('test.txt:1 1st match")); -> 개선방법#2 assertThat(out.contains("test.txt:1 1st match"), equals(true)); -> 개선방법#3 assertThat(out, containsString("text.txt:1 1st match"));
  • 30. 가독성#2 광역 단언 • 너무 작은 부분까지 단언하려는 집착으로
 하나만 잘못되어도 바로 실패.
 의도했던 핵심 단언이 나머지 단언에 묻힘. • 로그파일에 대한 검증
 광대한 로그파일. 사소한 부분의 변화에도 실패 • assertEquals(expectedOutput, output.content());
  • 31. 가독성#3 비트 단언 • assertTrue(Platform.IS_32_BIT ^ Platform.IS_64_BIT); • 비트 연산에 익숙한 프로그래머는 많지 않다.
  • 32. 가독성#4 부차적 상세정보 • 읽기 쉬운 코드는 읽는 이에게 그 의도와 목적, 의미를 빠 르게 보여준다. • 그리고 프로그래머는 코드를 훑을 때 본질이 무엇인가를 찾을 뿐, 자잘한 내용은 크게 신경 쓰지 않음. • 테스트 코드에 부수적인 정보가 넘쳐나 본질이 숨으면? • 테스트 의도를 파악하기 위해 코드를 빙빙~ 돌아야하면?
  • 33. 가독성#4 부차적 상세정보 • 핵심이 아닌 설정은 private 메서드나 셋업 메서드로 추 출 • 적절한 인자와 서술형 이름을 사용하라 • 한 메서드 안에서는 모두 같은 수준으로 추상화하라
  • 34. 가독성#5 다중인격 • 하나의 몸(메소드)에 여러개의 영혼(단언).
 테스트 개선 방법중 가장 쉬운 방법. • 하나의 테스트는 오직 한 가지만 똑바로 검색해야 한다.
 (테스트 당 단언문이 하나를 뜻하는 것은 아님) • test메소드에 객체를 생성하고 테스트 코드를 작성할때
 객체를 생성한 김에 다른 단언문도 몇개 추가해볼까?
  • 35. 가독성#6 쪼개진 논리 • 긴 코드가 나타나면 '흩어진 코드'를
 찾아 스크롤을 해야한다. • 로직을 찾아서.. 데이터 처리과정을 찾아서~
 이리저리 해메지 않도록 • 외부 데이터와 코드를 모두 테스트 안으로 옮기자! • ex) 첫번째 테스트는 변수 할당을 다루고
 두번째 테스트는 메서드 호출을 다루자 • 예제는 다음장에..
  • 36. 가독성#6 쪼개진 논리 다음과 같은 명령어가 포함된 쉘을 자바에서 실행 후 테스트를 진행한다면. sed -i “s/이스빈다/있습니다/g” welcome.txt 테스트 소스뿐만 아니라 쉘 파일까지 모두 검토 해야함. Eclipse IDE툴이 편리하다고는 하지만...
  • 37. 잠깐. 데이터와 로직의 분리기준 • 짧다면 통합하라 • 통합하기에 너무 길다면 
 팩토리 메서드나 테스트 데이터 생성기로 분리 • 이것도 쉽지 않다면 독립 파일로 남겨둬라
  • 38. 가독성#7 매직넘버 대부분의 프로그래머가 동의하는 매직넘버를 피하자 game.roll(10, 12); assertThat(game.score(), is(equalTo(300))); -> 개선방법#1 roll( pins(10), times(12)); -> 개선방법#2 roll(TEN_PINS, TWELVE_TIMES);
  • 39. 가독성#8 셋업 설교 • 셋업 메서드가 길고, 복잡하고 지루하다면? • 참고할만한 방법 3가지
 -셋업에서 핵심을 제외한 정보는 private 메소드로 추출
 -알맞은 서술적 이름을 사용
 -셋업 내의 추상화 수준을 통일 • 샘플코드는 다음장에…
  • 40. 가독성#8 셋업 설교 셋업 설교는 짧은 테스트를 위한 너무 긴 준비작업을 뜻한다. @Before public void setUp() throws Exception { String tempDir = System.getProperty("java.io.tmpdir"); tempDir = new File(tempDir, "2014"); tempDir.mkdir(); String fileSeparator = System.propertiesSystem("file.separator"); List<String> listWorkFiles = new ArrayList<String>(); listWorkFiles.add( ..... fileSeparator ....... ); listWorkFiles.add( ..... fileSeparator ....... ); listWorkFiles.add( ..... fileSeparator ....... ); ..기타 등등 코드...
  • 41. 가독성#8 셋업 설교 세부 정보를 추출하여 한결 명확해진 셋업의 모습 @Before public void setUp() throws Exception { tempDir = createTempDir("2014"); listWorkFiles = createWorkFileList(); .. .. }
  • 42. 가독성#9 과잉보호 테스트 진짜 단언문 앞에 불필요한 단언문이 있는경우. Data data = project.getData(); assertNotNull(data); assertEquals(4, data.count());
  • 44. 유지보수성#1 중복 상수 중복 그리고 메소드 중복 @Test public void emptyTemplate() throws Exception { assertEquals("", new Template("").evaluate()); } @Test public void plainTextTemplate() throws Exception { assertEquals("plaintext", new Template("plaintext").evaluate()); }
  • 45. 유지보수성#1 중복 1차 상수 중복 개선 (2차는 메소드 중복 개선) @Test public void emptyTemplate() throws Exception { String template = ""; assertEquals(template, new Template(template).evaluate()); } @Test public void plainTextTemplate() throws Exception { String template = "plaintext"; assertEquals(template, new Template(template).evaluate()); }
  • 46. 유지보수성#2 조건부 로직 • 테스트중에 실패가 확인되었다. • 어디서 실패가 나온건가? • 조건부 로직이 이를 방애한다.
  • 47. 유지보수성#2 조건부 로직 유지 보수를 어렵게 하는 테스트 코드 속의 조건부 로직 public void returnAnIteratorForContents() throws Exception { Dictionary dict = new Dictionary(); dict.add("A", new Long(3)); dict.add("B", "21"); for (Iterator e = dict.iterator(); e.hasNext();) { Map.Entry entry = (Map.Entry) e.next(); if ("A".equals(entry.getKey())) { assertEquals(3L, entry.getValue()); } if ("B".equals(entry.getKey())) { assertEquals("21", entry.getValue()); } } }
  • 48. 유지보수성#2 조건부 로직 @Test public void returnAnIteratorForcontents() throws Exception { Dictionary dict = new Dictionary(); dict.add("A", new Long(3)); dict.add("B", "21"); assertContains(dict.iterator(), "A", 3L); assertContains(dict.iterator(), "B", "21"); } private void assertContain(Iterator i, Object key, Object value) { while (i.hasNext()) { Map.Entry entry = (Map.Entry) i.next(); if (key.equals(entry.getKey()) { assertEquals(value, entry.getValue()); return; } } fail("Iterator didn't contain " + key + " => " + value); }
  • 49. 유지보수성#3 양치기 테스트 • 간헐적으로 실패하는 테스트. • 날짜, 시간에 따라 동작이 다르거나
 입출력, CPU 부하, 네트워크에 따라 다른 결과
  • 50. 유지보수성#4 파손된 파일 경로 테스트를 순식간에 망가뜨릴 수 있는 절대 경로 new File(“C:workspacecatalog.xml”); -> 개선방법#1 new File("/workspace/catalog.xml"); -> 개선방법#2 new File(“./src/test/data/catalog.xml");
  • 51. 유지보수성#5 끈질긴 임시 파일 • 가장 먼저.. 파일이 꼭 있어야 하는가? • 테스트에 사용한 임시파일이
 다음 테스트까지 남아 있다면? • @Before 메서드에서 파일을 삭제하라
 가능하면 임시 파일명도 유일하게 지어라 • File.createTempFile("catalog", ".xml", DirectoryPath);
 JVM프로세스가 종료될 때에나 지워지기 때문에 비추천
  • 52. 유지보수성#6 잠자는 달팽이 • 메모리는 빠르지만
 디스크, Network은 상대적으로 느리다 • 또한 Thread.sleep() 역시 느.리.다. • 예제코드는 다음장에.. • Thread가 동작하는것에 대해
 충분한 시간(sleep())을 준다는것은 비효율. • java.util.concurrent패키지의
 CountDownLatch() 활용
  • 53. 유지보수성#6 잠자는 달팽이 Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { values.add(counter.getAndIncrement()); } } for (int i=0; i < 10; i++ ) { new Thread(runnable).start(); } Thread.sleep(500); assertEquals(.., ..);
  • 54. 유지보수성#8 파라미터화된 혼란 • 파라미터화된 테스트 패턴 이란?
 데이터를 아주 조금씩만 바꿔가며 수차례 반복적인 검사. • 나쁜냄새가 나는 코드 • JUnit이 제공하는 방법 • 여러 단언문을 하나의 메서드로 합치는 방법
  • 55. 유지보수성#8 파라미터화된 혼란 @Test public void testOne() { assertEquals("I", format(1)); } public void testTwo() { assertEquals("II", format(2)); } public void testThree() { assertEquals("III", format(3)); } public void testFour() { assertEquals("IV", format(4)); }
  • 56. 유지보수성#8 파라미터화된 혼란 @RunWith(Parameterized.class) public class RomanNumeralsTest { private int number; private String numeral; public RomanNumeralsTest(int number, String numeral) { this.number = number; this.numeral = numeral; } @Parameters public static Collection<Object[]> data() { return asList(new Object[][] { { 1, "I" }, { 2, "II" }, { 3, "III" }, { 4, "IV" } } } @Test public void formatsPositiveIntegers() { assertEquals(numeral, format(number)); } } 하지만 테스트 결과가 익명으로 보여짐.
  • 57. 유지보수성#8 파라미터화된 혼란 여러 단언문을 하나의 메서드로 합치기 public void formatsPositiveIntegers() { assertEquals("I", format(1)); assertEquals("II", format(2)); assertEquals("IV", format(4)); assertEquals("V", format(5)); }
  • 58. 유지보수성#9 메서드간 응집력 결핍 • OOP 의 개념중
 낮은 결합도, 높은 응집력 • 각각의 테스트 메소드가 일부 픽스처만 사용 • 픽스처(Fixture)란?
 테스트를 수행하는데 필요한 정보나 객체들 • 예제코드는 다음장에..
  • 59. 유지보수성#9 메서드간 응집력 결핍 public class AccountTest { Account account; Rule rule1, rule2, rule3, rule4; .. @Test public void testCalcTax() { List list = new Array.... ... create(rule1, 1500); create(rule2, 80); } @Test public void testCalcFee() { List list = new Array.... ... create(rule3, 1500); create(rule4, 80); }
  • 61. 신뢰성#1 주석으로 변한 테스트 • 특정 테스트 메소드 전체가 주석이 되어 있다면? • 주석처리한 이유를 찾기 위해 아까운
 프로그래머의 시간을 좀먹게 한다. • 안쓰는건지?
 특수한 상황에서만 써야하는건지?
 혼란스러워진다. • 최고의 방법은 지워버리자!
  • 62. 신뢰성#2 오해를 낳는 주석 • 실제 동작과 다른 주석이 있다면?
 이런 불일치를 그대로 믿고 진행한다면? • 주석 대신 더 적절한 변수명/메서드명 사용 • 주석이 사용된 부분을 의미있는 메소드명으로 분리
  • 63. 유지보수성#3 절대 실패하지 않는 테스트 코드가 정상동작한다면 catch 블록이 예외를 잡아서 결과는 성공 코드가 비정상동작하여 예외가 발생하지 않으면 테스트 메서드는 정상 종료 @Test public void includeForMssingResourceFails() { try { new Environment().include("없는 자원"); } catch (IOException e) { assertThat(.e.getMessage(), contains("없는 자원")); } }
  • 64. 유지보수성#3 절대 실패하지 않는 테스트 개선 코드 public void includeForMssingResourceFails() { try { new Environment().include("없는 자원"); fail(); } catch (IOException e) { assertThat(.e.getMessage(), contains("없는 자원")); } }
  • 65. 유지보수성#3 절대 실패하지 않는 테스트 더욱 좋은방법은 @Test 애너테이션에 expected 속성 사용 @Test(expected = IOException.class) public void includeingMissingResourceFails() { new Environment().include("실존하지 않는 자원"); }
  • 66. 신뢰성#4 지키지 못할 약속 • 아무 '일'도 안하는 테스트 • '무언가 일은 하지만, 정작 '검증'은 안하는 테스트 • 이름값 못하는 테스트
  • 67. 신뢰성#4 지키지 못할 약속 아무 '일'도 안하는 테스트 @Test public void testFilteringObject() throws Exception { //List list........ //String result = create(........ //... //... //assertThat(........, .......); }
  • 68. 신뢰성#4 지키지 못할 약속 '무언가 일은 하지만, 정작 '검증'은 안하는 테스트 테스트 메소드에 단언문이 없다면? Exception이 발생하지 않는 한 정상
  • 69. 신뢰성#4 지키지 못할 약속 이름값 못하는 테스트 @Test public void zipBetweenTwoArraysProducesAHash() throws Exception { ... ... ... assertNotNull("We have a hash back", zipped.flatten(); }
  • 70. 신뢰성#5 낮아진 기대치 종종 게으르고 가장 쉬운 길로 가려는 경향. 쉬운 방법이 옳을 수도 있지만.. 정도가 심하다면? double sample1 = calc1.cal(); double sample2 = calc2.cal(); assertThat(sample1, is(greaterThan(0.0))); assertThat(sample2, is(greaterThan(0.0))); assertTrue(sample1 != sample2);
  • 71. 신뢰성#6 플랫폼 편견 • JAVA가 제창하던
 Write Once, Run Anywhere
 
 하지만 실패.. • 플랫폼 편견이란 필요한 플랫폼을 모두
 다루지 못하는 것.