[테스트 주도 개발] 26장_빨간 막대 패턴

이 패턴들은 테스트를 언제 어디서 작성할 건지, 테스트 작성을 언제 멈출지에 대한 것이다.

한 단계 테스트

목록에서 다음 테스트를 고를 때 무엇을 기준으로 골라야 할까? 새로운 무언가를 가르쳐 줄 수 있고, 구현할 수 있는 확신이 드는 테스트를 골라라.

시작 테스트

어떤 테스트부터 시작하는게 좋을까? 오퍼레이션이 아무 일도 하지 않는 경우를 먼저 테스트해라.

설명 테스트

자동화된 테스트가 널리 쓰이게 하려면 어떻게 해야할까? 테스트로 설명을 요청하고 테스트로 설명해라.
예를 들어, 누군가 시퀀스 다이엄드램을 설명하라고 하면, 시퀀스 다이어그램의 모든 요소를 포함하는 테스트케이스를 작성해라.

학습 테스트

외부에서 만든 소프트웨어에 대한 테스트를 작성해야 할 때도 있나? 패키지의 새로운 기능을 처음 사용해보기 전에 할 수 있다.
자바의 모바일 정보 기기 프로파일 라이브러리르 기반으로 뭔가를 만든다고 하자. 그냥 바로 사용하는 대신 API 가 우리 예상대로 실행된다는 것을 확인해줄만한 테스트를 먼저 만들어라. 만약, 테스트가 통과하지 않으면 애플리케이션 역시 실행되지 않을것이므로 애플리케이션을 실행해볼 필요도 없다.

또 다른 테스트
Read more

[테스트 주도 개발] 27장_테스팅 패턴

이 패턴들은 더 상세한 테스트 작성법에 대한 것이다.

자식 테스트

지나치게 큰 테스트 케이스를 어떻게 돌아갈 수 있을까 ? 원래 테스트 케이스의 깨지는 부분에 해당하는 작은 테스트 케이스를 작성하고 그 작은 테스트케이스가 실행되도록 해라. 그 후에 다시 원래의 큰 테스트 케이스를 추가해라.

Mock Object

비용이 많이 들거나 복잡한 리소스에 의존하는 객체를 테스트하려면 어떻게 해야할까 ? 상수를 반환하게끔 만든 속임수 버젼의 리소스를 만들면 된다.
예를 들어, 데이터베이스는 시작 시간이 오래 걸린고 깨끗한 상태를 유지하기 어렵다. 그리고 만약 데이터베이스가 원격 서버에 있다면 테스트 성공 여부가 네트워크 상의 물리적인 영향을 받게 된다. 또, 데이터베이스는 개발 중 많은 오류의 원인이다. 해법은, 진짜 데이터베이스를 사용하지 않는 것이다.
모의 객체를 사용하면 성능과 견고함 이외에, 가독성이 좋아진다. 또한, 가시성에 대해 고민하도록 격려해서 설계에서 커플링이 감소하도록 한다.
하지만 모의 객체를 사용하면, 프로젝트에 위험 요소가 추가된다. 모의 객체가 진짜 객체와 동일하게 동작하지 않으면 어떻게 될까 ? 모의 객체용 테스트 집합을 진짜 객체가 사용 가능해질때 그대로 적용해서 이 위험을 줄일 수 있다.

Crash Test Dummy

호출되지 않을 것 같은 에러코드를 어떻게 테스트할 것인가 ? 실제 작업을 수행하는 대신 그냥 예외를 발생시키기만 하는 특수한 객체를 만들어서 호출한다.
파일 시스템에 여유 공간이 없을 경우 발생할 문제에 대해 테스트를 해보자. 자바의 익명 내부 클래스는 테스트하기 원하는 메서드만이 오류를 발생하게끔 하기 위해 유용하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
void testFileSystemError(){
File file = new File("foo") {
public boolean createNeweFile() throws IOException {
throw new IOException();
}
};

try {
saveAs(file);
fail();
} catch (IOException e){

}
}
깨진 테스트

혼자서 프로그래밍할 때 프로그래밍 세션을 어떤 상태로 끝내는게 좋을까 ? 마지막 테스트가 깨진 상태로 끝내라.
나중에 다시 코딩할 때, 어느 작업부터 시작할 것인지 명백히 알 수 있다. 전에 하고 있던 생각에 대한 명확하고 구체적인 책갈피를 가지는 것이다.

Read more

[테스트 주도 개발] 28장_초록 막대 패턴

코드가 테스트를 통과하게 만들기 위해 이 패턴들을 사용해라.

가짜로 구현하기 ( 진짜로 만들기 전까지만 )

실패하는 테스트를 만든 후 첫 번째 구현은 어떻게 하는게 좋을까? 상수를 반환하게 하라. 일단 테스트가 통과하면 단계적으로 상수를 변수를 사용하는 수식으로 변형한다.

삼각 측량

오로지 예가 두개 이상일 때만 추상화를 해라.
두 정수 합을 반환하는 함수를 예로 보자.

1
2
3
4
@Test
void testSum(){
assertEquals(4, plus(3,1));
}
1
2
3
private int plus(int augend, int addend) {
return 4;
}

삼각 층량을 사용해서 바른 설계로 간다면, 다음과 같이 작성해야한다.

1
2
3
4
5
@Test
void testSum(){
assertEquals(4, plus(3,1));
assertEquals(7, plus(3,4));
}

그러면, 우리는 plus 의 구현을 추상화 할 수 있다.

Read more

[빅데이터] 5장_일괄처리 계층의 데이터 저장소 : 사례

HDFS 를 사용하는 방법과, 상위 수준 API 를 사용하여 필요한 작업을 자동화하는 방법을 정리한다. 항상 그랬듯이, 도구를 비교하는 것이 아니라 상위 수준의 개념을 보강하는 것이 목적이다.

5.1 하둡 분산 파일 시스템 사용하기

HDFS 의 동작 방식을 정리하면,

  1. 파일은 블록으로 쪼개져서 클러스터에 있는 여러 노드로 퍼뜨려진다.
  2. 블록은 여러 노드로 복제되어서 장비가 다운되어도 데이터는 여전히 사용 가능하다.
  3. 네임노드는 각 파일이 어떤 블록으로 구성되는지와, 그 블록이 어디에 저장되어 있는지를 추적한다.

파일과 폴더를 조작하는 HDFS API 사용법을 보자. 서버에 로그인한 정보를 모두 저장한다고 하자.

1
2
3
4
5
$ cat logins-2020-03-31.txt
jko 192.168.12.125 Thu Mar 31 22:33 - 22:46
jh 192.168.12.125 Thu Mar 31 21:15 - 22:42
ko 192.168.12.125 Thu Mar 31 23:31 - 22:13
jko 192.168.12.125 Thu Mar 31 22:33 - 22:43

이 데이터를 HDFS 에 저장하려면 데이터 집합 저장용 디렉토리를 우선 만들고 올리면 된다. 파일을 올리면 자동으로 블록으로 쪼개져서 여러 데이터 노드 사이에 분산된다.

1
2
$ haddop fs -mkdir /logins
$ haddop fs -put logins-2020-03-31.txt /logins
5.1.1 작은 파일 문제

하둡은 데이터가 HDFS 상의 여러 작은 파일에 저장되어있을 때는, 계산 성능이 떨어지는 특성이 있다.
그 원인은, 맵리듀스 작업이 입력 데이터 집합의 각 블록마다 테스크를 하나씩 실행하기 때문이다. 각 테스크는 실행을 계획하고 조정하는 오버헤드를 소모하는데, 각각의 작은 파일은 독립적인 테스크에서 실행되어야하므로, 그 비용은 반복적으로 발생한다.

Read more

[테스트 주도 개발] 22장_실패 처리하기

  • 테스트 메서드 호출하기
  • 먼저 setUp 호출하기
  • 나중에 tearDown 호출하기
  • 테스트 메서드가 실패해도 tearDown 호출하기
  • 여러 개의 테스트 실행하기
  • 수집된 결과를 출력하기
  • WasRun 에 로그 문자열 남기기
  • 실패한 테스트 보고하기

실패한 테스트를 발견하면, 세밀한 단위의 테스트를 작성해서 올바른 결과를 출력해보자.

1
2
3
4
5
6
// TestCaseTest
def testFailedResultFormatting(self):
result = TestResult()
result.testStarted()
result.testFailed()
assert ("1 run, 1 failed" == result.summary())

실패 횟수를 세어보자.

1
2
3
4
5
6
// TestResult
def __init__(self):
self.runCount = 0
self.failureCount = 0
def testFailed(self):
self.failureCount = self.failureCount + 1

이제 출력하자.

1
2
3
// TestResult
def summary(self):
return "%d run, %d failed" % (self.runCount, self.failureCount)

이제 테스트 메서드에서 예외를 잡으면, testFailed() 를 호출하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
// TestCase
def run(self):
result = TestResult()
result.testStarted()
self.setUp()

try:
method = getattr(self, self.name)
method()
except:
result.testFailed()
self.tearDown()
return result

run() 에는 문제가 있다. 바로 setUp()에서 문제가 발생한 경우에는 예외가 잡히지 않는다는 것이다. todo list 에 넣어두자.

Read more