단위테스트(Unit test) 개념과 python에서 사용하기

recoDeQ·2023년 8월 1일
0

시스템 개발

목록 보기
1/2

단위 테스트

1. 정의

테스트란?
소프트웨어가 요구사항에 부합하여 개발되었는지 검증

유닛 테스트(unit tezt)란?
응용 프로그램에서 테스트 가능한 가장 작은 소프트웨어를 실행하여 의도된 대로 정확하게 작동하는지 검증


2. 장점과 단점

(장점)
1) 개발 과정 중에 문제를 미리 발견할 수 있다.
2) 코드 변경에 따른 영향도 파악이 용이하다.
3) 코드 리팩토링을 안심하고 할 수 있다.
4) 오래 전 짠 코드에 대한 파악 및 인수인계가 용이하다.
5) 테스팅에 대한 시간과 비용을 절감할 수 있다.
6) 새로운 기능 추가 시에 수시로 빠르게 테스트할 수 있다.
7) 코드에 대한 문서가 될 수 있다.

(단점)
1) 코드 유지 보수 관리가 늘어난다.
2) 다른 객체와 메세지를 주고 받는 객체의 경우 다른 객체 대신에 가짜 객체(Mock Object)를 주입하여 어떤 결과를 반환하도록 정해진 답변을 준비해야 하는 Stub가 발생한다.


3. 단위 테스트 프로세스와 구조

1) 준비(Arrange, Given)

2) 실행(Act, When)

3) 검증(Assert, Then)


4. 좋은 단위 테스트

1) 리팩토링 내성

  • 테스트를 바꾸지 않고 기본 애플리케이션 코드를 리팩토링할 수 있도록 함(거짓 양성)

2) 테스트 결과 피드백의 스피드

  • 즉각적인 테스트 통과/실패가 나오는 단위
    => 코드의 변경마다 실행이 용이하도록 함
    => 리소스가 낭비 방지

3) 회귀 방지

  • 테스트가 가능한 한 많은 코드를 실행하는 것을 목표로 함(거짓 음성)

4) 유지보수성

  • 테스트 이해 용이성
  • 테스트 실행 용이성
  • 테스트 정확도 = 신호(발견된 버그 수) / 소음(허위 경보 발생 수)
  • 블랙 박스를 기본으로 선택
    => 블랙 박스 : 내부 구조를 몰라도 시스템의 기능을 검사할 수 있는 방법
    => 화이트 박스 : 내부 작업을 검증하는 테스트 방식으로 명세가 아닌 소스 코드에서 파생

5. 작성 규칙

[테스트 코드 5가지 규칙 - FIRST!]

Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.

Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다.

Repeatable: 어느 환경에서도 반복 가능해야 한다.

Self-Validating: 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.

Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.


6. 작성 방법

1) 각 단위테스트는 독립적으로 이뤄지며(하나의 테스트 케이스에 대한 최소한 기능만 검증) 최대한 간경하게 작성한다.

1개의 테스트 함수에 대해 assert를 최소화하라

1개의 테스트 함수는 1가지 개념 만을 테스트하라

2) 입력값에 대한 결과 값을 검증하는 방식으로 작성한다.

3) Third Party Library의 기능은 제외한다.


7. 테스트 실패시

1) 코드 수정하기 (테스트 코드 수정이나 예외처리보다는 코드에서 해결하자!)

2) 테스트 케이스 추가하기


8. python 단위 테스트, unittest

1) unittest 프레임워크 소개

  • python의 표준 라이브러리
  • Junit의 단위 테스트를 참조하였고, 다른 언어의 주요 단위 테스트 프레임워크와 비슷한 특징을 가지고 있음
  • 테스트 자동화, 테스트를 위한 사전 설정(setup)과 종료(shutdown) 코드 공유, 테스트를 컬렉션에 종합하기, 테스트와 리포트 프레임워크의 분리 등을 지원함

    테스트 픽스펴 : 1개 또는 그 이상의 테스트를 수행할 때 필요한 준비와 그와 관련된 정리 동작, 테스트 실행 환경(setUp(), tearDown())

    테스트 케이스 : 테스트의 개별 단위

    테스트 묶음 : 테스트 케이스, 테스트 묶음, 또는 둘 다의 모임으로 서로 같이 실행되어야 할 테스트들의 종합

    테스트 실행자 : 테스트 실행을 조율하고 테스트 결과를 사용자에게 제공하는 역할을 하는 컴포넌트

2) unittest 구조 및 작성 유의 사항

  • unittest.TestCase : 테스트 실행자가 테스트를 실행할 수 있는 인터페이스를 구현하고 테스트 코드가 검사, 실패 보고를 할 수 있는 메서드 구현
    • setUp() : 테스트 이전에 실행(사전 설정 코드), 테스트 프레임워크가 1개의 테스트마다 매번 자동으로 호출함
    • tearDown() : 테스트 메서드 실행 이후에 정리하는 메서드(테스트 성공 여부와 상관없이 setUp()이 성공하면 실행됨)
    • setUpClass() :

주의사항
1) test*.py 파일로 별도로 빼서 관리 및 테스트를 권장한다.
2) 테스트 진행하는 함수는 함수명의 앞에 test
*()로 만든다

3) unittest 간단한 예시

step1 : 테스트 실행하여 성공 여부 보기

import unittest

def myfunc():
   print(f'test 모듈 실행합니다')

class CustomTests(unittest.TestCase):
   def test_runs(self):
       myfunc()

if __name__ == '__main__':
   unittest.main()

step1 실행 : python ./파일명.py

step1 결과

step2 : setUp() / tearDown() 사용하기

  • 사용예 : DB 연결 등이 필요할 때 사용

import unittest

def myfunc(num):
    print(f'test 모듈 {num}번을 실행합니다')

class CustomTests(unittest.TestCase):
    def setUp(self) -> None :
        self.num = 5 
    
    def tearDown(self) -> None :
        self.num = 10 

    def test_runs(self) -> None :
        myfunc(self.num)

if __name__ == '__main__':
    unittest.main()

step2 결과

step3 : 테스트 케이스 인자를 넣어서 결과 확인하기

import unittest

def myfunc(num):
    print(f'test 모듈 {num}번을 실행합니다')
    # return num # 주석 풀면 정상 실행 됨

class CustomTests(unittest.TestCase):
    def setUp(self) -> None :
        self.num = 5 
    
    def tearDown(self) -> None :
        self.num = 10 

    def test_runs(self) -> None :
    	# assertEqual == 값이 같은 경우 Success , 다른 경우 Fail
        self.assertEqual(myfunc(self.num), 5 , 'incorrect num') 


if __name__ == '__main__':
    unittest.main()

step3 : 결과1 - return을 주석처리한 경우 테스트 Fail 발생

step3 : 결과2 - return을 주석 해제한 경우 테스트 성공

4) unittest의 assert메소드 리스트

메서드검사하는 내용추가된 버전
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) is True
assertFalse(x)bool(x) is False
assertIs(a, b)a is b3.1
assertIsNot(a, b)a is not b3.1
assertIsNone(x)x is None3.1
assertIsNotNone(x)x is not None3.1
assertIn(a, b)a in b3.1
assertNotIn(a, b)a not in b3.1
assertIsInstance(a, b)isinstance(a, b)3.2
assertNotIsInstance(a, b)not isinstance(a, b)3.2
assertRaises(exc, fun, *args, **kwds)fun(*args, **kwds)가 exc를 발생
assertRaisesRegex(exc, r, fun, *args, **kwds)fun(*args, **kwds)가 exc를 발생하고 메시지가 정규식 r에 일치3.1
assertWarns(warn, fun, *args, **kwds)fun(*args, **kwds)가 warn을 발생3.2
assertWarnsRegex(warn, r, fun, *args, **kwds)fun(*args, **kwds)가 warn을 발생하고 메시지가 정규식 r에 일치3.2
assertLogs(logger, level)with 블록이 최소 level로 logger에 로그를 남김3.4
assertNoLogs(logger, level)The with block does not log onlogger with minimum level

[참조-테스트 정의]

[참조-테스트 작성]

[참조-python unittest 모둘]

profile
개발 스터디 노트입니다.

0개의 댓글