프로그래밍웹 교과서
이 페이지의 목차
1단원 · 5차시

단계마다 조심할 것

제약 조건모듈단위 테스트통합 테스트시스템 테스트

학습 목표

  • 개발 단계별로 유의해야 할 사항을 설명한다.
  • 단위 테스트와 통합 테스트, 시스템 테스트의 목적을 구분한다.

관련 성취기준

  • 프그01-02

    프로그램을 효율적으로 개발하기 위한 체계적인 절차와 단계별로 유의해야 할 사항에 대하여 설명할 수 있다.

생각 열기 — 완성한 날 들은 말

3주 동안 성적 처리 프로그램을 만들었다. 코드는 한 줄도 오류가 없고 실행도 잘 된다. 자랑스럽게 보여 드렸더니 이런 말이 돌아왔다.

“평균이 소수점 한 자리까지 나와야 하는데요. 그리고 결시생은 평균에서 빼야 합니다.”

요구 사항 분석에서 — 애매한 말을 남기지 않는다

요구 사항에 애매한 말이 남아 있으면 만드는 사람과 쓰는 사람이 서로 다른 것을 생각한 채 3주가 흐른다. 애매한 말을 숫자와 규칙으로 바꾸는 일이 이 단계의 핵심이다.

애매한 요구 사항을 확정하는 방법
들은 말되물어야 할 질문확정된 요구 사항
"평균을 보여 주세요"소수점 몇 자리까지? 반올림인가 버림인가? 결시생은 어떻게?평균은 소수점 첫째 자리까지 반올림하고, 결시생은 인원수에서 뺀다
"빠르게 처리되게 해 주세요"몇 명 기준으로 몇 초 안인가?300명 자료를 3초 안에 처리한다
"많은 학생을 넣을 수 있게"최대 몇 명인가?한 번에 최대 500명까지 넣는다
"쓰기 편하게 해 주세요"누가 쓰는가? 무엇을 몇 번 눌러야 하는가?담임 교사가 쓰며, 파일을 고른 뒤 단추 한 번으로 결과가 나온다
"잘못된 값은 걸러 주세요"점수 범위는? 걸렀을 때 어떻게 알리는가?0 미만 또는 100 초과는 받지 않고, 몇째 줄이 잘못됐는지 알린다

요구 사항에는 해야 할 일 말고 지켜야 할 조건도 있다. 이것을 제약 조건(constraint) — 프로그램이 반드시 지켜야 하는 한계나 환경 조건이라 한다. 학교 컴퓨터에 프로그램을 새로 설치할 수 없다는 조건, 인터넷이 끊겨도 돌아가야 한다는 조건, 개인정보를 저장하지 않아야 한다는 조건이 그렇다. 제약 조건은 늦게 알면 만든 것을 버려야 하므로 1단계에서 반드시 확인한다.

설계에서 — 한 덩어리에 한 가지 일만 맡긴다

설계에서 프로그램을 나누는 덩어리를 모듈(module) — 한 가지 일을 맡아 처리하는 프로그램의 부분이라 한다. 모듈을 잘 나누는 기준은 셋이다.

  • 기준 1

    한 가지 일만 한다

    "파일을 읽고 평균을 내고 화면에 그린다"는 세 모듈로 나눈다. 한 모듈이 세 일을 하면 하나를 고칠 때 셋이 흔들린다.

  • 기준 2

    이름으로 설명된다

    "성적파일읽기"처럼 하는 일이 이름에 담기면 잘 나뉜 것이다. 이름을 짓기 어렵다면 아직 한 가지 일이 아니다.

  • 기준 3

    남의 속을 몰라도 쓴다

    평균을 내는 모듈은 파일을 어떻게 읽었는지 몰라도 된다. 값만 받으면 된다. 이렇게 하면 한쪽을 바꿔도 다른 쪽이 멀쩡하다.

구현에서 — 몇 달 뒤에 읽을 사람을 생각한다

코드를 읽는 사람은 대체로 몇 달 뒤의 자기 자신이다. 그때 알아볼 수 있게 쓰는 것이 구현 단계의 유의 사항이다.

  • 이름에 뜻을 담는다. a, b, x1 대신 점수합계, 학생수처럼 무엇을 담는지 알 수 있게 짓는다. 이름을 잘 지으면 설명이 줄어든다.
  • 같은 코드를 여러 곳에 복사하지 않는다. 복사한 코드는 고칠 때 한 곳만 고쳐지고 나머지는 남는다. 이것이 오래 찾지 못하는 잘못의 흔한 원인이다. 같은 일을 하는 코드는 한 곳에 모으고 불러 쓴다.
  • 주석에는 ’무엇’이 아니라 ’왜’를 적는다. 점수합계 = 점수합계 + 점수 옆에 “점수를 더한다”고 적는 것은 도움이 되지 않는다. 코드에 이미 적혀 있다. 대신 “결시생은 0점이 아니라 제외해야 하므로 여기서 걸러 낸다”처럼 코드만 봐서는 알 수 없는 판단의 이유를 적는다.
  • 한 번에 조금씩 만들고 확인한다. 200줄을 다 쓴 뒤 처음 실행하면 어디가 잘못됐는지 찾기 어렵다. 20줄마다 실행해 보면 방금 쓴 부분이 범인이다.

테스트에서 — 세 단계로 나눠 확인한다

테스트는 한 번에 전체를 보는 것이 아니라 범위를 넓혀 가며 세 번 한다.

시스템 테스트 — 실제 환경에서 전체를 요구 사항과 대조한다통합 테스트 — 이어 붙였을 때 주고받는 값이 맞는지 본다기능 A단위 테스트기능 B단위 테스트기능 C단위 테스트실제 사용자실제 자료실제 컴퓨터안쪽을 먼저 확인해야 밖에서 문제가 났을 때 원인을 좁힐 수 있다.
세 가지 테스트의 범위. 안쪽에서 밖으로 넓혀 가며 확인한다.자체 제작
세 가지 테스트의 목적과 확인 대상
테스트확인 범위무엇을 보는가여기서 잡히는 잘못의 예
단위 테스트모듈 하나이 모듈이 정한 입력에 정한 결과를 내는가평균 계산에서 인원수로 나누지 않고 더한 값만 돌려준다
통합 테스트모듈을 이어 붙인 부분모듈끼리 주고받는 값의 모양과 뜻이 맞는가읽기 모듈은 문자열로 넘기는데 계산 모듈은 숫자를 기다린다
시스템 테스트완성한 프로그램 전체요구 사항 명세서의 모든 항목을 지키는가300명 자료를 3초 안에 처리한다는 조건을 못 지킨다

세 단계로 나누는 이유는 원인을 좁히기 위해서다. 전체를 한 번에 돌려 보고 결과가 틀렸다면 어느 모듈이 범인인지 알 수 없다. 단위 테스트를 먼저 통과시켜 두면 통합 테스트에서 나는 문제는 “모듈 사이”의 문제로 좁혀진다.

테스트할 값을 고르는 법 — 되는 경우만 넣지 않는다

테스트에서 가장 흔한 실수는 잘 되는 값만 넣어 보는 것이다. 확인해야 할 값은 네 갈래다.

0 이상 100 이하의 점수를 받는 프로그램의 테스트 값
갈래넣어 볼 값기대하는 동작
정상값75정상 처리한다
경계값0, 100정상 처리한다 — 경계를 포함하는지가 실수가 잦은 곳이다
경계 바로 밖-1, 101받지 않고 잘못된 값임을 알린다
잘못된 형식"칠십오", 빈 값, 공백프로그램이 멈추지 않고 잘못을 알린다
분류하기테스트 값을 네 갈래로 나눠 보자 — 「0 이상 100 이하의 점수」

카드를 누른 뒤, 넣을 통을 누른다. 통 안의 카드를 누르면 다시 나온다.

정상값

경계값

경계 바로 밖

잘못된 형식

빈칸 채우기테스트의 세 범위

부품 하나가 제대로 도는지 보는 것이 1, 부품을 이어 붙여 주고받는 값이 맞는지 보는 것이 2, 완성한 프로그램을 실제로 쓸 환경에서 처음부터 끝까지 써 보는 것이 3다.

정답 보기
  1. 단위 테스트
  2. 통합 테스트
  3. 시스템 테스트

유지 보수에서 — 고친 뒤 이미 되던 것을 다시 시험한다

유지 보수의 가장 큰 함정은 한 곳을 고쳐 다른 곳이 깨지는 일이다. 결시생 처리를 고쳤더니 전체 인원수를 세는 부분이 틀어지는 식이다.

그래서 코드를 고친 뒤에는 새로 고친 부분만 확인하는 것으로 끝내지 않는다. 이미 잘 되던 기능들도 다시 시험한다. 이것을 회귀 테스트(regression test)라 한다. 앞 단계에서 테스트 값을 목록으로 남겨 두면 이 일이 목록을 한 번 훑는 일이 된다. 남겨 두지 않으면 매번 처음부터 다시 생각해야 한다.

활동

토의

요구 사항을 잘못 파악해 생긴 실패 사례 분석

약 20분

아래 두 사례를 읽고 모둠에서 분석한다.

사례 1 — 동아리 신청 프로그램을 만들었다. 학생이 이름과 희망 동아리를 넣으면 명단에 저장된다. 신청 첫날, 같은 학생이 다섯 번 신청한 기록이 쌓였고 정원이 20명인 동아리에 43명이 들어갔다. 만든 학생은 “중복 신청을 막아 달라는 말은 없었다”고 했다.

사례 2 — 도서 대출 프로그램을 만들었다. 시험 삼아 5권을 넣었을 때는 잘 됐다. 실제로 도서실 자료 8,400권을 넣자 목록을 여는 데 40초가 걸려 아무도 쓰지 못했다.

각 사례를 다음 형식으로 정리한다.

  1. 어느 단계에서 생긴 잘못인가 — 요구 사항 분석 / 설계 / 구현 / 테스트 중에서 고르고 이유를 적는다.
  2. 어느 단계에서 발견됐는가 — 1번과 다르다면, 그 사이에 무엇을 헛일로 만들었는가.
  3. 1단계에서 무엇을 되물었어야 하는가 — 실제 질문 문장으로 적는다.
  4. 어떤 테스트 값을 넣었어야 발견됐는가 — 사례 2는 특히 이 항목을 자세히 적는다.

발표 뒤 두 사례의 공통점을 한 문장으로 정리한다. “말하지 않았다”와 “묻지 않았다” 중 누구의 책임인지 따지는 토의로 흐르지 않게 한다. 절차의 목적은 책임을 가리는 것이 아니라 같은 일이 다시 생기지 않게 하는 것이다.

개념 확인 문제

보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.

요구 사항 분석 단계에서 '빠르게 처리되게 해 주세요'라는 말을 들었을 때 가장 알맞은 대응은?프그01-02

모듈을 잘 나눈 것인지 판단하는 기준으로 알맞지 않은 것은?프그01-02

파일을 읽는 모듈은 점수를 문자열로 넘기는데, 계산 모듈은 숫자를 기다리고 있어 오류가 났다. 이 잘못을 잡아내는 테스트는?프그01-02

0 이상 100 이하의 점수를 받는 프로그램을 테스트할 때, 다음 중 반드시 넣어 보아야 하지만 가장 자주 빠뜨리는 값은?프그01-02

[OX] 코드를 고친 뒤에는 고친 부분만 확인하면 충분하다.프그01-02

더 알아보기

사례단위를 맞추지 않아 잃어버린 탐사선

1999년, 미국 항공우주국의 화성 기후 탐사선(Mars Climate Orbiter)이 화성 궤도 진입에 실패해 사라졌다. 조사 결과 원인은 계산 실수가 아니라 단위 불일치였다. 한쪽 기관이 만든 프로그램은 힘의 값을 파운드힘 단위로 내놓았고, 이를 받아 쓰는 항법 프로그램은 그 값을 뉴턴 단위로 읽었다. 두 프로그램은 각각 정확하게 동작했다. 둘 사이에 주고받는 값의 단위를 명세로 못 박아 두지 않은 것이 문제였다. 통합 단계에서 확인해야 할 것이 무엇인지 보여 주는 사례다.

심화테스트를 먼저 쓰는 방법

코드를 쓴 뒤 테스트하는 대신, 테스트를 먼저 적고 그것을 통과하는 코드를 쓰는 방식이 있다. 예를 들어 평균 계산 모듈을 만들기 전에 “80과 90을 넣으면 85가 나온다”, “빈 목록을 넣으면 오류를 알린다”를 먼저 적어 둔다. 이렇게 하면 두 가지 효과가 있다. 첫째, 무엇을 만들지 명확해진다. 테스트를 적으려면 입력과 출력을 정해야 하기 때문이다. 둘째, 회귀 테스트 목록이 저절로 쌓인다. 이 방식을 테스트 주도 개발이라 부른다.

실무잘못을 부르는 이름들

같은 것을 가리키는 말이 여러 개 쓰인다. 코드에 적힌 문법이 어긋난 것은 문법 오류, 문법은 맞지만 계산이나 판단이 틀린 것은 논리 오류라 한다. 실행 중에 프로그램이 멈추는 것은 실행 오류다. 이 셋 중 논리 오류가 가장 찾기 어렵다. 프로그램이 멈추지도 않고 오류 메시지도 없이, 그냥 답이 틀리기 때문이다. 논리 오류를 찾는 유일한 방법은 미리 정한 기대 결과와 대조하는 것, 즉 테스트다.

이어지는 학습

이 차시를 이해하려면 다음을 먼저 알아야 한다.

  • 4차시의 개발 절차 단계 — 프로그래밍 프그01-02

교과서에서 찾기

교과서해당 위치쪽수
성림출판(Python)프로그래밍의 개요 › 02 프로그래밍의 절차26쪽
씨마스커뮤니케이션(Python)프로그래밍 개요 › 2 프로그래밍 절차24쪽
삼양미디어(Python)프로그래밍의 개요 › 02 프로그래밍의 절차와 알고리즘 (프그01-03과 통합)22쪽
삼양미디어(C)프로그래밍의 개요 › 02 프로그래밍의 절차와 알고리즘 (프그01-03과 통합)22쪽
씨마스(C)프로그래밍의 개요 › 2 프로그래밍의 절차24쪽
웅보출판사(C)프로그래밍의 개요 › Chapter 02 프로그래밍의 절차23쪽