NLP Blog

C++ 더 쉽고, 더 깊게 - chap 11. 구조체

|

Chapter 11. 구조체

여러값을 하나로 묶기

  • 지금까지는 한 종류의 값 (ex. int, float…)을 배열(array)에 저장
  • 하지만 처리할 데이터가 많아지면 서로 연관된 데이터를 다루어야 할 때도 많아짐
  • 예를들어, 비디오 게임에서는 플레이어의 이름뿐만 아니라 와편 좌표 (x, y) 도 저장 해야 함. 이를 기존 방식으로 생각하면
    int x_coordinates[ 10 ];
    int y_coordinates[ 10 ];
    string names[ 10 ];
    
  • 하지만 이 세 배열은 서로 짝을 이루고 있으므로, 어느 한 배열에서 요소의 위치를 옮기면 다른 두 배열에서 이와 연관된 요소도 함께 옮겨야 함 (ex. sort)
  • 만약 네 번째 값을 추적해야 한다면 상당히 어려워짐 (ex. HP gage).
    • 네 번째 배열 추가
    • 처음의 세 배열과 동기화
  • 요런 귀찮을거 막기위해 구조체가 있다!
    • 여러 데이터를 한데 모아야 할 때 유용

###문법

  • 구조체를 정의하기 위한 문법은 다음과 같다
    struct SpaceShip
    {
    int x_coordinate;
    int y_coordinate;
    string name;
    };
    
  • 여기서 ShapeShip은 구조체라는 특별한 타입의 이름이다.
  • 기존의 int나 double처럼 우리가 직접 타입을 만든 것
  • 다음과 같이 선언 가능
SpaceShip my_ship;

my_ship.x_coordinate = 40;
my_ship.y_coordinate = 40;
my_ship.name = "USS Enterprise (NCC-1701-D)";
  • x_coordinate, y_coordinate, name은 새로 만들어진 타입의 필드다

  • 다음의 예시 프로그램은 다섯 명의 플레이어의 이름을 읽는 프로그램인데, 게임자체는 포함되지 않으며, 배열과 구조체가 함께 사용

#include <iostream>

using namespace std;

struct PlayerInfo
{
    int skill_level;
    string name;
};

int main()
{
    // 일반적인 변수 타입처럼 구조체도 배열로 만들 수 있다.
    PlayerInfo players[ 5 ];
    for ( int i = 0; i < 5; i++ )
    {
        cout << "Please enter the name for player : "
            << i << endl;
        // 우선 일반적인 배열 문법으로 배열의 요소에 접근한 다음,
        // '.' 문법으로 구조체의 필드에 접근
        cin >> players[ i ].name;
        cout << "Please enter the skill level for "
            << players[ i ].name << endl;
        cin >> players[ i ].skill_level;
    }
    for ( int i = 0; i < 5; ++i)
    {
        cout << players[ i ].name
            << " is at skill level "
            << players[ i ].skill_level << endl;
    }
}
  • PlayerInfo 구조체에서는 두 가지 필드를 선언
    • 플레이어의 이름
    • 플레이어의 skill_level
  • PlayerInfo를 여느 변수 처럼(ex. int) 사용할 수 있으므로, 플레이어들의 배열을 만들수도 있음
    • 구조체로 배열을 만들면 배열의 각 요소를 구조체의 인스턴스처럼 다룰 수 있음
    • 배열에서 첮 번째 구조체의 필드는 배열의 첫 번째 요소에서 플레이어의 이름에 해당
      • players[ 0 ].name으로 접근 가능
  • 이 프로그램에서는 다섯 명의 플레이어 정보를 읽어 들이기 위한 배열과 구조체를 두 종류의 데이터와 하나의 루프로 결합한 다음, 두 번째 루프에서 이 정보를 표시할 수 있는 능력을 적극 활용
  • 데이터를 처리하기 위한 배열을 따로 둘 이유도 없고, player_names와 player_skill_level 배열도 따로 둘 이유가 없음

구조체 전달하기

  • 구조체를 인수로 받거나 리턴하는 함수를 작성해야 할 때가 있음
    • ex. 우주선을 조작하는 게임에서 새로운 적에 해당하는 구조체를 초기화 해보자

```cpp struc Enemy

Comment  Read more

Deep Learning Book - chap 2. Linear Algebra

|

chapter 2. 선형 대수

2.1 scalar, vector, matrix, tensor

  • scalar :
    • 그냥 하나의 수
    • 이탤릭체 사용, 변수의 이름은 흔히 영문 소문자 사용
    • 해당 변수가 나타내는 수들의 종류도 명시 (ex: $ {\it s} \in \mathbb{N}$ 스칼라 s는 자연수이다. )
  • vector :
    • 여러 개의 수를 특정한 순서로 나열한 것
    • 벡터에 있는 특정한 하나의 수, 즉 벡터의 한 성분은 벡터 안에서의 그 성분의 위치를 뜻하는 index를 이용하여 지칭
    • 굵은 영문 소문자로 표기 ($ \bf{x}$)
    • 벡터의 개별 성분을 지칭할 때는 벡터 이름을 굵지 않은 이탤릭으로 표기하고 색인은 아래첨자로 표기 ($x_1, x_2 …$)
    • 벡터에 담긴 수들의 종류도 명시해줌
    • 공간의 한 점을 식별하는 값으로 간주 가능
  • Matrix :
    • 수들을 2차원으로 배열한 것
    • 특정한 한 정분을 지칭하려면 하나가 아니라 두 개의 색인이 필요
    • 실숫값 행령 ${\bf A}$의 높이가 m이고 너비가 n일 때, 이를 ${\bf A} \in \mathbb{ R }^{m \times n}$ 이라고 표현함
    • 행렬에서 수직 좌표성분이 $i$인 성분들을 한꺼번에 지칭할 때는 수평 좌표성분에 :을 지정 (ex: ${\bf A}_{i,:}$는 수직 좌표가 $i$인 수평 성분들을 뜻함 -> row)
  • Tensor :
    • 차원이 셋 이상인 배열을 사용해야 할 때도 있음
    • 2차원 행렬을 일반화해서, 수들의 배열을 임의의 개수의 ㅣ축을 가진 정규 격자 형태로 배치한 것

  • transpose(전치) :
    • 원래의 행렬을 주대각(main diagonal) 대칭으로 반사한 것
    • $(\bf{ A }^\top)_{i,j} $ $= \bf{ A }_{j,i}$

2.2 행렬과 벡터의 곱셉

  • 행렬곱
    • 행렬 $\mathbf{ A }$와 $\mathbf{ B }$를 곱하면 새로운 행렬 $\mathbf{ C }$가 된다
    • 이러한 행렬곱이 정의되려면 $\mathbf{ A }$의 열 수가 $\mathbf{ B }$의 행 수와 같아야 함
    • $\mathbf{ C } = \mathbf{ AB }$ -> $C_{i,j} = \sum_kA_{i,k}B_{k,j}$
    • 분배법칙 만족
    • 결합법칙 만족
    • 교환법칙 불만족
  • 성분별 곱 or Hadamard product
    • $\bf{A}\bigodot\bf{B}$ 로 표기
  • 일차 연립 방정식을 행렬과 벡터로 표현 가능
    • $\bf{A}\bf{x} = \bf{b}$ —– (eq 2.11)
    • 여기서 $\bf{A}\in\mathbb{ R }^{m \times n}$ 은 알려진 행렬, $\bf{b}\in\mathbb{ R }^m$은 알려진 벡터, 그리고 $\bf{x}\in\mathbb{ R }^n$은 방정식을 풀어서 알아내고자 하는 미지수들로 이루어진 벡터이다.

2.3 단위행렬과 역행렬

  • eq 2.11을 해석적으로 풀 수있는 강력한 수단이 있는데 고것이 역행렬!
  • 먼저 단위행렬 부터 알아보자

2.3.1 단위 행렬

  • 단위행렬은 그것에 어떤 벡터를 곱해도 원래의 벡터가 그대로 나오는 행렬
  • 주대각 성분들만 1이고 다른 모든 성분은 0

2.3.2 역행렬

  • 행렬 $\bf{A}$의 역행렬을 $\bf{A}^{-1}$로 표기
  • 다음과 같이 정의 : $\bf{A}^{-1}\bf{A} = \bf{I}_n$
  • eq 2.11은 이제 다음과 같이 풀 수 있다

\(\bf{Ax} = \bf{b}\) \(\bf{A}^{-1}\bf{Ax} = \bf{A}^{-1}\bf{b}\) \(\bf{I}_n\bf{x} = \bf{A}^{-1}\bf{b}\) \(\bf{x} = \bf{A}^{-1}\bf{b}\)

  • 물론 요론 계산은 $\bf{A}^{-1}$를 구할 수 있을때만 가능
  • $\bf{A}^{-1}$가 존재한다고 할 때, 그것의 닫힌 형식을 구하는 알고리즘이 여러 개 있다.
    • 같은 역행렬을 서로 다른 $\bf{b}$에 대해 사용해서 방정식을 여러번 풀 수 있음, 이론적으로
    • 그러나 $\bf{A}^{-1}$는 이론상의 도구로 유용할 뿐!
    • 컴퓨터는 $\bf{A}^{-1}$을 제한된 정밀도(부동소수점 표현)으로 표현하므로 대체로 $\bf{b}$의 값들을 활용하는 알고리즘들이 $\bf{x}$를 좀 더 정확하게 추정할 수 있다

2.4 일차종속과 생성공간

  • $\bf{A}^{-1}$이 존재하려면, 모든 $\bf{b}$값에 대해 eq 2.11에 정확히 하나의 해가 있어야 한다.
  • 일부 $\bf{b}$값에 대해서는 해가 하나도 없거나 무한히 많아도 역행렬이 존재할 수 있다
  • 그러나 특정 $\bf{b}$에 대해 해의 개수가 둘 이상, 무한대 미만인 경우가 있어서는 안된다.
  • $\bf{x}$와 $\bf{y}$가 둘 다 유효한 해라고 할 때, 임의의 실수 $\alpha$에 대해 아래의 해도 유효한 해이다. \(\bf{z} = \alpha\bf{x} + (1-\alpha)\bf{y}\)

Comment  Read more

Data Structure & Implements 2 - Linked List

|

자료 구조

4. Linked List

4.1 정의

Linked List

  • A Linked List consist of many nodes
  • A LINK contains address of (= points to) the next node.
  • Address of nodes is not sequential (Address of nodes may change on run time)
    • Array와 가장 다른 점
  • Size of a linked list is not predefined.
  • There is a pointer pointing to the first node of a linked list.
  • There is a special address value(=NULL) at the last node

4.2 Array와 Linked List의 차이점

4.2.1 Array

  • Sequential representation
  • Insert & Delete : Inefficient due to data shift - O(n)
  • Size of data must be predefined
  • Static storage allocation (during compile time)

4.2.2 Linked List

  • **Non-sequential representation
  • Insert & Delete : Efficient due to avoiding data shift - O(1)
  • Size of data needs not to be predefined
  • Dynamic storage allocation (during run time)

4.3 Allocation/Deallocation

  • (Memory) Allocation
    • Get a currently available node.
    • malloc Function
    • linked list malloc
  • (Memory) Deallocation
    • Return a no longer unused node
    • free function
    • linked list free

4.4 Mechanisms

4.4.1 Simple Insertion

  • To insert ‘eat’ between ‘cat’ and ‘fat’
    • linked list simple insertion1
    • Newly allocate a node by a pointer variable p, and stroe ‘eat’ at the node’s DATA.
    • Assign the LINK of p to the node after “cat”, which contains “fat”.
    • Assign the LINK of the node “cat” to p.
    • linked list simple insertion2

4.4.2 Simple Deletion

  • To delete ‘fat’ from the list
    • linked list deletion1
    • Assign the LINK of ‘fat’ node to the LINK of ‘cat’ node
    • Return (deallocate) the ‘fat’ node by using free
    • linked list deletion2

4.4.3 Node Definition

  • Define the node, named ‘list_node’, by using struct
  • Each list_node consist of two fields, DATA and LINK
  • list_ptr is a pointer type pointing to the next list_node
  • prt is a pointer variable defined on *list_ptr, initially NULL
  • linked list node definition

4.5 Operators

4.5.1 Basic Operations

  • All the variables p, q, r, ... are list_ptr type
  • Initialize Pointer Value:
    • p = NULL
  • Move to the next node:
    • p = p -> LINK
    • p->LINK
  • Assign Pointer value : Sharing the same node
    • q = p, q = r, ...
  • Compare Pointer Values : only permit ==, !=
    • if (p == q) then ...
    • if (p != q) then ...
    • if (p == NULL) then ...
    • if (p -> LINK == NULL) then ...

4.5.2 Insert

  • To do this, three variables* are required.
    • ptr : pointing to the first node in a list
    • ins : pointing to the insert position
    • new : pointing to the new node
  • Two cases are considered
    • case 1 : list is empty (i.e., ptr is NULL)
    • case 2 : list is not empty (i.e., ptr)
    • prt is null?
  • linked list insert
void Insert (list_ptr *ptr, list_ptr ins) {
  list_ptr new;
  new = (list_ptr) malloc(sizeof(list_node));
  new -> data = 25;
  if (*ptr != NULL) { /*In case, list is not empty*/
    new -> link = ins -> link;
    ins -> link = new;
  }
  else { /*In case, list becomes empty*/
    new -> link = NULL;
    *ptr = new;
  }
}

linked list insert2

4.5.3 Delete

  • To this end, three variables are also required.
    • ptr : pointing to the first node in a list
    • del : pointing to the delete position
    • pre : pointing to the preceding node w.r.t the delte node
  • Two cases exist w.r.t the delete position
    • case 1 : the fisrt node in a list (i.e., prev is NULL)
    • case 2 : other nodes except the first node (i.e., ptr in not NULL)
    • linked list del
void Delete(list_ptr *ptr, list_ptr pre, list_ptr del){
  if (pre != NULL){
    ///In case, the delete node is not the first node
    pre -> link = del -> link;
  }
  else{ ///In case, the delete node is the fisrt node
    *ptr = (*ptr) -> link;
    free(del); ///Deallocate the delete node
  }
}

4.5.4 Traverse

linked list traverse

Comment  Read more

Data Structure & Implements 1 - Array, Stack, Queue

|

자료 구조

1. Array

array

1.1 정의

  • A set of pairs, <index, value> such that each index has a value associated with it
    • 모든 값은 같은 데이터 타입을 가져야 한다.
    • 연속적 메모리 공간에 allocation 됨
    • 메모리 사이즈가 정해지면, 런타임 동안에는 수정 불가

    array-definition

1.2 특징

  • Sequential representation
    • 메모리 상에 연속적으로 선언되어 있음
  • Insert & Delete : Inefficient due to data shift - O(n)
    • 데이터를 array 중간에 넣거나 삭제하려면, 나머지 데이터의 이동이 발생하여 비효율 적
  • Size of data must be predefined
    • 메모리 상에 연속적으로 선언되어야 하므로, array의 크기는 compile time에 미리 선언되어야 함
  • Static storage allocation
    • 앞과 같은 이유로 프로그램 수행 도중에 사이즈를 바꿀 수 없음

1.3 Operator & Time Complexity

  • Retrieve(A, i) : array A에 i-index의 값을 가져오기
  • Store(A, i, X) : array A에 i-index에 X값을 넣음
    • 위 두개의 operator는 index가 메모리에 위치적으로 연속하기 때문에 direct access가능!, time complexity O(1)

  • Insert(A, i, X): array A의 i-index에 X값을 삽입
    • 위의 Store와 다르게, 뒤쪽에 있는 데이터를 한칸씩 밀어야함
    • 비효율적! O(n)

  • Delete(A, i) : array A의 i-index의 값을 삭제하고 뒤에 있는 데이터를 당김
    • data movement 발생!
    • 비효울적! O(n)

1.4 2-Dimensional array

  • m & n 의 row, column 테이블이 표현하고 싶을 때 2차원 array 필요

2d array

  • 대부분의 element가 0인 경우 Sparse Matrix 사용을 고려
    • Sparse Matrix : 2-D array -> <row index, column index, non-zero value>

2. Stack

2.1 정의

  • A list whose end points are pointed by top and bottom
    • 양 마지막 부분이 topbottom으로 point된 리스트
  • Insertion and deletion take place at the top
    • top부분에서만 삽입삭제가 이루어진다.
  • Bottom is constant, but top grow and shrinks
  • Not possibple to access the items within stack, except top!
  • LIFO (Last-In First-Out)

2.2 Implementation : Use of array

  • Use one-dimensional Array
  • Use one variable : top
  • Always initialize the top by -1

2.2.1 Operators : Push and pop

  • Push : Insert an item into a stack
    void push (int top, element item){
    if(top >= MAX_STACK_SIZE -1) return stack_full();
    top = top + 1;
    stack[top] = item;
    }
    
  • Pop : Delete an item from a stack
    element pop(int top){
    if (top == -1) return stack_empty();
    item = stack[top];
    top = top -1;
    }
    

stack pop push

2.3 Stack의 활용

  • Evaluation of Arithmetic Expressions
  • Maze Problem
  • Parsing (Pattern Matching)
  • Function Calls/Returns
  • Queens Problem
  • Backtracking

3. Queue

3.1 정의

queue

  • A list whose ends are pointed by front and rear
    • stack과 비슷하면서도 다름
  • Insertion and deletion take place at rear and front, repectively
    • stack과 다른 점
  • Not possible to acceess all items except front and rear
    • stacktop만 접근 가능
  • FIFO (First-In First-Out)

3.2 Implementaion : Use of Array

  • Use one-dimensional array
  • Use two variables : front, rear
  • Initialize always both front and rear by -1

queue init

3.2.1 Operators : Insert / Delete

  • Insert queue insert
    Insert(element item){
    if (rear == MAX_Q_SIZE-1) return queue_full();
    rear = rear + 1;
    queue[rear] = item;
    }
    
  • Delete queue delete
    Delete(){
    if (front == rear) return queue_empty();
    front = front + 1;
    item = queue[front];
    }
    

3.3 Problems

  • Queue always moves to the right direction.
  • Queue_full(i.e., rear == MAX_Q_SIZE - 1) condition does not always mean that there are maximum items in queue
    • front가 delete() 가 call 될 때마다 +1 되므로, array의 앞부분이 버려진 채로 남게 된다.
  • There still may be empty spaces available even if queue is full.
  • If you wnat to insert an item, all data should be moved!
    • In the worst case, O(n) - Inefficient
  • Solution - Circular Queue

3.4 Circular Queue

circular queue

  • front + 1 is the same as the actual front value
  • rear is the same as the actual rear value

circular queue2

3.4.1 Operator

  • Insert
    • Increment “rear” by “1” in a clockwise direction;
    • if “rear” reaches the end of queue, reset “rear” by “0”
    • Queue Full Condition : front == rear
      Insert(element item){
      rear = (rear + 1) % MAX_Q_SIZE  ///Circluar !
      if (front == rear) return queue_full();
      queue[rear] = item;
      }
      
  • Delete
    • Increment “front” by “1” in a clockwise direction;
    • circular queue delete
    • if “front” reaches the end of queue, reset “front” by “0”
    • Condition of Queue Empty : front == rear
      Delete(){
      if (front == rear) return queue_empty();
      front = (front + 1) % MAX_Q_SIZE;
      item = queue[front]
      }
      

3.5 Problem

  • full and empty condition is the same!
  • Solution
    • option1 :
      • Only permit MAX_Q_SIZE -1 elements; (one space in a queue is not used)
      • But, at rear == front, reset the rear with the prior position (i.e., rear = rear -1)
      • circular queue solution1
    • option2 : A Boolean variable (e.g: Tag) is additionally used
      • After insert/ delete, set the Tag to true/false
      • Queue is empty if (front == rear) && ! Tag
      • Queue is full if (front == rear) && Tag

3.6 Queue: Applications

  • Job Processing (printer, CPU processor)
  • Data Buffers
  • Waiting times of customers at a public phone
  • Deciding number of cashiers (tellers) at super market (bank)
  • Traffic Analysis

Comment  Read more

이펙티브 파이썬 - 56. unittest로 모든 것을 테스트 하자

|

BetterWay 56. unittest로 모든 것을 테스트 하자

  • 파이썬에는 정적 타입 검사 기능이 없음…. 컴파일러는 프로그램이 제대로 동작함을 보장하지 않음
    • c, java 같은 경우는 syntax error같은거를 binary 만들어주는 compiler 동작때 모두 잡아줌
  • 파이썬으로는 프로그램에서 호출하는 함수가 런타임에 정의되어 있을지 알 수 없으며, 심지어 해당 함수가 소스코드에 있다고 해도 알 수 없다.
  • 일례로, 동적 임포트의 부작용으로 SyntaxError제품에서 발생함

  • 이러한 문제점을 잡아내기 위해서는 테스트가 필수적! 어떤 언어로 프로그램을 작성하든!
  • 다행히 파이썬에서는 동적 기능이 파이썬의 정적 타입 검사는 방해하지만, 동시에 코드 테스트를 아주 쉽게 작성할 수 있게 해줌
  • 파이선의 동적 특성과 쉽게 오버라이드할 수 있는 동작으로 테스트를 구현하여 프로그램이 예상대로 잘 동작함을 보장 할 수 있음

  • 테스트는 코드에 대한 보장 정책
  • 좋은 테스트는 코드가 올바르게 동작한다는 신회를 줌
  • 코드를 리팩토링하거나 확장하는 용도로 테스트를 사용하면, 동작이 어떻게 바뀌는지 쉽게 구별할 수 있음
  • 테스트를 작성하는 가장 간단한 방법은 내장 모듈unittest를 사용하는 것

  • 예를 들어 utils.py에 다음과 같은 유틸리티 함수를 정의했다고 하자
# utils.py
def to_str(data):
    if isinstance(data, str):
        return data
    elif isinstance(data, bytes):
        return data.decode('utf-8')
    else:
        raise TypeError('Must supply str or bytes, ' 'found: %r' % data)
  • 기대하는 각 동작에 대한 테스트를 담은 test_utils.py라는 두번째 파일을 생성 (utils_test.py)
# utils_test.py
from unittest import TestCase, main
# from utils import to_str

class UtilsTestCase(TestCase):
    def test_to_str_bytes(self):
        self.assertEqual('hello', to_str(b'hello'))

    def test_to_str_str(self):
        self.assertEqual('hello', to_str('hello'))

    def test_to_str_bad(self):
        self.assertRaises(TypeError, to_str, object())

#if __name__ == '__main__':
#    main()
E
======================================================================
ERROR: /Users/minhopark/Library/Jupyter/runtime/kernel-0e8bea65-c31a-4cea-928e-764744e126c2 (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute '/Users/minhopark/Library/Jupyter/runtime/kernel-0e8bea65-c31a-4cea-928e-764744e126c2'

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (errors=1)



An exception has occurred, use %tb to see the full traceback.


SystemExit: True



/Users/minhopark/tensorflow/lib/python3.5/site-packages/IPython/core/interactiveshell.py:2918: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
  • TestCase 클래스는 테스트에서 assertion을 하는 데 필요한 헬퍼 메서드를 제공
    • 동등성 검사 assertEqual
    • bool 표현식 검사 assertTrue
    • 적절할 때 예외가 발생하는지 검사하는 assertRaises
    • … 자세한거는 help(TestCase)로 확인 요망
  • TestCase 서브 클래스에 자신만의 헬퍼 메서드를 정의하여 테스트를 더 이해하기 쉽게 만들 수 있다.
    • 헬퍼 메서드의 이름이 test로 시작하지 않게만 하면 됨

note

  • 테스트를 작성할 때 다른 일반적인 관례는 mock함수로 클래스의 특정 동작을 제거하는 것
  • 파이썬3는 이런 목적으로 내장 모듈 unittest.mock을 제공 (참고 python mock)

  • 때때로 TestCase클래스에서 테스트 메서드를 실행하기 전에 테스트 환경을 설정해야 함
    • setUp, tearDown Override 필요
  • 위 메서드 들은 각 테스트 메서드를 싱행하기 전후에 각각 호출
  • 각 테스트라 분리되어 실행됨을 보장 (적절한 테스트의 모범 사례)
  • ex) 각 테스트 전에 임시 디렉터리를 생성하고, 각 테스트가 종료한 후에 그 내용을 삭제하는 TestCase 정의
class MyTest(TestCase):
    def setUP(self):
        self.test_dir = TemporaryDirectory()
    def tearDown(self):
        self.test_dir.cleanup()
    # 테스트 메서드
    # ...
  • 보통 관련 테스트의 각 집합별로 TestCase하나 정의
  • 때때로 예외 상황이 많은 각 함수별로 TestCase만듦
  • 또는 때때로 TestCase하나로 한 모듈에 속한 모든 함수를 처리하기도 함
  • 또한 단일 클래스와 그 클래스의 메서드를 테스트할 용도로 TestCase를 생성하기도 함

  • 프로그램이 복잡해지면 코드를 별도로 테스트하는 대신에 모듈 간의 상호 작용을 검증할 테스트를 추가함 - Integration test (통합 테스트)
  • 파이썬도 또한 단위 테스트와 통합 테스트를 모두 진행해야 함

Note

  • 프로젝트에 따라 데이터 중심 테스트를 정의하거나 관련 기능을 다르게 묶어서 테스트를 구성하는 편이 유용 할 수 있음
  • 이런 목적과 코드 커버리지 보고서, 다른 고급 활용 사례에는 nosepytest 가 도움 된다.

핵심 정리

  • 파이썬 프로그램을 신뢰할 수 있는 유일한 방법은 테스트 작성!
  • 내장 모듈 unittest는 좋은 테스트를 작성하는 데 필요한 대부분의 기능을 제공
  • TestCase를 상속하고 테스트 하려는 동작별로 메서드 하나를 저으이해서 테스트를 정의 할 수 있음
  • TestCase클래스에 있는 테스트 메서드는 test라는 단어로 시작해야 함
  • 단위 테스트(고립된 기능용)와 통합 테스트(상호 작용하는 모듈용) 모두를 작성해야 함

Comment  Read more