베오
DCode
베오
전체 방문자
오늘
어제
  • 분류 전체보기 (218)
    • 공지사항 (1)
    • 잡설 (1)
    • Programming (33)
      • [C] (1)
      • [Java] (4)
      • [Python] (2)
      • [Android] (2)
      • [Network] (0)
      • [Operation System] (2)
      • [Spring Boot] (22)
      • [Docker] (0)
    • Algorithm (31)
      • 자료구조 (2)
      • 알고리즘 (Java) (14)
      • 알고리즘 (기초) (15)
    • Coding Test (131)
      • BOJ (131)
      • Algospat (0)
    • 이론적인거 (14)
      • 보안 (5)
      • 오류 해결 (2)
      • 디자인 패턴 (5)
      • 네트워크 (1)
      • 기타 (1)
    • 최신기술 (4)
      • 블록체인 (1)
    • [Project] (1)

블로그 메뉴

  • 🐈‍⬛ GitHub
  • 📫 방명록
  • 🔖 태그

공지사항

인기 글

티스토리

hELLO · Designed By 정상우.
베오

DCode

Programming/[Python]

[Python] 단위 테스트를 해보자 UnitTest

2022. 8. 30. 16:55

참조 문서 링크입니다.

전체 코드 링크입니다.

메소드명 설명
assertEqual(first, second, msg) first 와 second가 같은 지 확인
assertNotEqual(first, second, msg) first 와 second가 다른지 확인
assertTrue(expr, msg) expr 값이 True 인지 확인
assertFalse(expr, msg) expr 값이 False 인지 확인
assertIs(first, second, msg) first와 second가 같은 object 인지
assertIsNot(first, second, msg) first와 second가 같은 object가 아닌지
assertIn(member, container, msg) member가 container에 포함되는지
assertNotIn(member, container, msg) member가 container에 포함되지 않는 지
assertIsInstance(obj, cls, msg) obj가 cls의 인스턴스 인지
assertNotIsInstance(obj, cls, msg) obj가 cls의 인스턴스가 아닌지
assertRaises() 특정 예외가 발생했는지 확인

맛보기

전체 코드

import unittest

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # separator 가 string이 아닐 때
        with self.assertRaises(TypeError):
            s.split(2)

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

출력

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

테스트를 좀 더 자세하게 출력하고싶어요!

아래 unittest.main verbosity 인자의 값을 변경해준다.

unittest.main(verbosity=1(defualt))

값 설명
0 (quiet) 실행된 테스트의 수와 스킵된 테스트의 수만 확인할 수 있다.
1 (default) 성공된 테스트(.)와 실패한테스트(F) 가 몇 개 있는지 확인할 수 있다.
2 (verbose) 어느 테스트가 실행되었는지, 어느 테스트가 스킵되었는지 확인할 수 있다.

0 (quiet) 일 때

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

1 (default) 일 때

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

2 (verbose) 일 때

test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

테스트 케이스 구조 만들기

테스트 케이스는 클래스 형식 내에 메소드를 구현함으로써 수행한다.

테스트는 메소드명의 오름차순으로 실행된다.

setUp() : 사전 설정 코드 구현 → 테스트 메소드 호출 전 마다 호출

tearDown() : 사후 설정 코드 구현 → 테스트 메소드 호출 후 호출(실패/성공 모두 실행)

import unittest

class Widget:
    def __init__(self, widget_name: str):
        self.widget_name = widget_name
        self.width = 50
        self.height = 50

    def size(self):
        return self.width, self.height

    def resize(self, width: int, height: int):
        self.width = width
        self.height = height

    def dispose(self):
                pass

class DefaultWidgetSizeTestCase(unittest.TestCase):
    # 사전 설정 코드
    def setUp(self):
        print('테스트 케이스 시작')
        self.widget = Widget('The widget')

    def test_default_widget_size(self):
        widget = Widget('The widget')
        self.assertEqual(widget.size(), (50, 50))

    def test_widget_resize(self):
        self.widget.resize(100, 150)
        self.assertEqual(self.widget.size(), (100, 150),
                         'wrong size after resize')

    # 사후 설정 코드
    def tearDown(self):
        print('테스트 케이스 종료')
        self.widget.dispose()

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

사용자 설정 테스트 묶음 만들기

해당 클래스의 모든 테스트가 아니라 일부만 뽑아와서 테스트를 실행하고 싶은 경우이다.

전체코드

import unittest

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_widget_size'))
    suite.addTest(WidgetTestCase('test_widget_resize'))
    return suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

테스트 스킵하기

메소드 단위 뿐만 아니라 클래스 단위로도 스킵할 수 있다.

  • @unittest.skip(reason) : 무조건 스킵
  • @unittest.skipIf(condition, reason) : 조건을 만족하면 스킵
  • @unittest.skipUnless(condition, reason) : 조건을 만족하지 않으면 스킵
  • self.skipTest(reason) : 메소드 내에서 스킵
  • @unittest.expectedFailure : 실패를 예상하는 경우
import unittest

def external_resource_available():
    return True

class MyTestCase(unittest.TestCase):
    # 무조건 스킵하기
    @unittest.skip("demonstrating skipping")
    def test_nothing(self):
        self.fail("shouldn't happen")

    # 조건을 만족하면 스킵하기
    @unittest.skipIf(1 < 4, "not supported in this library version")
    def test_format(self):
        pass

    # 조건을 만족하지 않으면 스킵하기
    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
    def test_windows_support(self):
        pass

    # 테스트 메소드 내에서 스킵하기
    def test_maybe_skipped(self):
        if not external_resource_available():
            self.skipTest("external resource not available")

# 클래스 단위로 스킵하기
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

# 실패가 예상된다면 -> 테스트 케이스를 만들었으나, 버그|미완성 등으로 동작하지 않는 상태
class ExpectedFailureTestCase(unittest.TestCase):
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "broken")

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

예상된 실패 실패 시 처리 결과

test_fail (__main__.ExpectedFailureTestCase) ... expected failure
...
----------------------------------------------------------------------
Ran 11 tests in 0.006s

OK (skipped=3, expected failures=1)

예상된 실패 성공 시 처리 결과

test_fail (__main__.ExpectedFailureTestCase) ... unexpected success
...
----------------------------------------------------------------------
Ran 11 tests in 0.006s

FAILED (skipped=3, unexpected successes=1)

테스트 내에서 반복을 추적하고 싶다면…

self.subTest() 를 이용하여 반복을 추적하자

전체 코드

import unittest

class NumbersTest(unittest.TestCase):
    def test_even(self):
        """
        [0,5] 반복하면서 짝수 체크하기
        """
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)

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

출력

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=1)
[0,5] 반복하면서 짝수 체크하기
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\Users\kim\Desktop\test\test.py", line 137, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=3)
[0,5] 반복하면서 짝수 체크하기
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\Users\kim\Desktop\test\test.py", line 137, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=5)
[0,5] 반복하면서 짝수 체크하기
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\Users\kim\Desktop\test\test.py", line 137, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

----------------------------------------------------------------------
저작자표시 (새창열림)

'Programming > [Python]' 카테고리의 다른 글

[Python] Logging 모듈을 사용해보자  (0) 2022.08.28
    'Programming/[Python]' 카테고리의 다른 글
    • [Python] Logging 모듈을 사용해보자
    베오
    베오

    티스토리툴바