TEAMLAB

Human knowledge belongs to the world . -AntiTrust

(11) 테스트와 디버깅

MIT - Introduction to Computer Science and Programming in Python

valiation

설계한 프로그램이 우리가 원하는 답을 준다는 확신을 갖기 위해서 증명이 필요하다.
증명하기 위한 두 가지 방법(testing&debugging)의 조화가 균형적이어야 한다. 그리고 두 가지 모두를 증명하는 과정의 부분으로 행한다.

Testing

테스팅은 프로그램을 돌리는 것이다.
기본적으로 2종류의 테스팅이 있다.

  1. Unit Testing
    어떤 프로그램을 각각 독립적으로 쓸 수 있는 unit 테스팅이 있다.
  2. Integration Testing(통합시험)

교수님의 메세지

  • 항상 각각의 unit을 테스팅한 후 실행시키기. 그러니까 프로그램을 실행시키기 전에 각각 하나씩 테스트 해보자. 전체를 테스트하는 것보다 작은 것 하나씩 하는 것이 더 쉽다.

Debugging

디버깅은 기본적으로 왜 프로그램이 작동하지 않는 지를 확인하는 과정이다. 단순히 검색의 과정이다.
디버깅의 목표는 한 개의 버그를 제거하는 것이 아니라는 것을 잊으면 안되는 것이다. 즉, 버그가 없는 프로그램을 만드는 것이 목표이다.

디버그하는 것도 테스팅처럼 전체를 하는 것보다 작은 것 하나씩 하는게 더 쉽다.
만약 프로그램이 크다면, 첫 번째 시도할 때 절대로 바로 작동되지 않는다. 왜 작동이 되지 않는지 찾아내고 시도해보려면 결국은 하나씩 테스팅하게 된다.

- Defensive Programming(방어 프로그램)

가끔, 여러분들은 디버깅을 하는데 많은 시간이 걸릴것이다. 왜 우리가 원하는 만큼 빠르게 답을 주지 않는 것인가?
이 때, 방어 프로그램이 매우 유용하게 쓰인다.

방어프로그램이 무엇인가
함수를 구현화하고 모듈화한다. 이 때, 문제를 빨리 발견하기 위해 statement를 확실히 사용해야한다. 그 후, 다시 실행과 디버깅으로 돌아오는 것이다.

- 버그에 대해 여러분이 잘 못 알고 있는 2가지 사실

  1. 버그가 프로그램 안으로 기어들어 온다는 것이다.
    만약 프로그램에 버그가 있다면, 실수인 것이다. 사실 버그보다 더 어울리는 단어는 실수이다.

  2. 버그가 번식한다
    절대 그렇지않다. 프로그램에 많은 버그가 있다면 그것은 여러번 실수를 했다는 것이다.

- debugger

최소 40년 동안, 사람들은 버그를 찾는 것을 도와주는 debugger를 만들어왔다. 가장 좋은 디버깅 툴은 항상 대부분 그래왔던 것 같이 현재와 같다.
print statementreading 이다. 또한, 버그를 잡으면서 검색 공간을 줄이는 좋은 디버거는 조직적으로 버그를 잡는 방법을 발달시켜 왔다.

조직적으로 버그를 잡는 방법이란

디버깅은 문제가 존재함을 알아낼 때에 시작된다.
제일 먼저해야 할 일은 program text를 공부하고 어떻게 이 결과가 나왔을까하고 묻는 것이다.
버그가 어떤 집단의 한 부분인지와 어떻게 버그를 고쳐야하는가는 과학적 방법을 활용한다.

과학적 방법
유용한 데이터를 연구하는 것을 처음 시작이라고 한다. 이런 경우, 유용한 데이터는 테스트 결과들과 program text이다.
이 때, 테스트 결과란 실행되지 않은 것 뿐만아니라 실행된 것 까지의 모든 테스트 결과를 의미한다.

그리고 나서 모든 데이터가 일치되는 가설을 만드는 것이다. 가설을 만들 땐, 이 실험이 타당한 과학적 실험이 되고, 행해지기 위해서 가설을 반박하는 가능성을 꼭 가져야만 한다.
가설 설정 후, 가설이 잘못되었는지 아닌지를 증명하기 위해 결과가 어떻게 되어야만 하는지 꼭 알아야한다.

- 실험 설계

두 개의 목표가 있다.

  1. 버그를 유발시키는 단순한 입력 값을 찾는 것
    종종 프로그램이 오랫동안 실행되고 갑자기 버그가 나타나는 케이스

  2. 필시 잘못되어있는 프로그램 부분을 찾는것
    이진 탐색을 추천한다.

e.g.1) 버그가 있는 프로그램

>>> def silly():
...     res = []
...     done = False
...     while not done:
...             elem = input('Enter element. Return when done.')
...             if elem == '':
...                     done = True
...             else:
...                     res.append(elem)
...     tmp = res
...     tmp.reverse()
...     isPal = (res == tmp)
...     if isPal:
...             print('is a palindrome')
...     else:
...             print('is not a palindrome')
...
>>> silly()   # 맞는 output
Enter element. Return when done.1
Enter element. Return when done.'a'
Enter element. Return when done.1
Enter element. Return when done.
is a palindrome
>>> silly()  # 틀린 output
Enter element. Return when done.1
Enter element. Return when done.'a'
Enter element. Return when done.2
Enter element. Return when done.
is a palindrome #버그가 있다.

e.g.2) binary search로 버그 잡기

>>> def silly():
...     res = []
...     done = False
...     while not done:
...             elem = input('Enter element. Return when done.')
...             if elem == '':
...                     done = True
...             else:
...                     res.append(elem)
...     #print('res should be [1,a,2]: ', res)
...     tmp = res[:]
...     #print('tmp', tmp, 'res', res)
...     tmp.reverse()
...     isPal = (res == tmp)
...     #print('tmp', tmp, 'res', res)
...     if isPal:
...             print('is a palindrome')
...     else:
...             print('is not a palindrome')
...
>>> silly()
Enter element. Return when done.1
Enter element. Return when done.'a'
Enter element. Return when done.2
Enter element. Return when done.
is not a palindrome

교수님의 메세지

  • 디버깅 과정에서 인내는 매우 중요하다.