TIL no.84 - Python - Django - Unit Test

박준규·2019년 11월 21일
4

Unittest에 관해 포스팅하겠습니다.

먼저, test의 종류는 다음과 같습니다.

  1. UI Testing / End-To-End Testing
    application이 시작부터 끝까지 예상대로 작동하는지 테스트하는 것입니다.
    실행하기 쉽다는 장점이 있지만
    비용이 많이 들고 부정확 하며 실행 시간이 오래 걸립니다.
    또한, 자동화와 실행이 까다롭습니다.

  2. Integration Testing
    Integration testing (I&T)은 개별적인 소프트웨어 모듈들이 합쳐져 그룹으로 테스트되는 단계입니다.
    Integration Testing이 End-To-End Testing 다음으로 공수가 많이 듭니다.

  3. Unit Testing
    Unit Testing은 소프트웨어의 개별적인 unit을 테스트하는 단계입니다. 설계한 대로 개별 unit들이 동작하는지 평가하기 위해 수행됩니다. 여기서 unit은 test할 수 있는 가장 작은 단위를 뜻합니다. 가장 쉬우며 가장 효과가 좋습니다.

UI Testing은 10%
Integrating Testing은 20%
그리고 Unit Testing을 70%로
전체 테스트 coverage를 구현 하는것이 권장됩니다.

TestTest Coverage
End-To-End Test10%
Integration Test20%
Unit Test70%

1. Unit Test

함수 혹은 메서드를 테스트합니다.
python에는 unittest라는 유닛테스트를 가능케 해주는 표준 라이브러리가 존재합니다.

Python Unit Test 용어 및 개념

용어개념
TestCaseunittest 프레임 워크의 테스트 조직의 기본 단위
Fixture테스트를 진행할때 필요한 테스트용 데이터 혹은 설정 등을 이야기 한다. 주로 테스트 가 실행되기 전이나 후에 생긴다.
assertionunittest에서 테스트 하는 부분이 제대로 됬는지를 확인하는 부분. Assertion이 실패하면 테스트도 실패한다.

예제를 살펴보면서 UnitTest에 대해 알아보겠습니다.

먼저, Test를 진행할 코드부터 작성하겠습니다.

#mycalc.py
def add(a, b):
    return a + b

def substract(a, b):
    return a - b

그리고 Test 코드를 작성하겠습니다.

# tests.py
import unittest
import mycalc

class MyCalcTest(unittest.TestCase): #unittest.TestCase를 상속받은 Test Class

    def test_add(self): #test_ 라는 이름으로 시작하는 메소드는 모두 테스트 메소드가 됩니다.
        c = mycalc.add(20, 10)
        self.assertEqual(c, 30)

    def test_substract(self):
        c = mycalc.substract(20, 10)
        self.assertEqual(c, 10)

if __name__ == '__main__':
    unittest.main() #unittest.main() 코드를 통해 테스트가 수행됩니다.

저장한 뒤, unittest를 실행하면 결과를 볼 수 있습니다.

$ python -m unittest --v
test_add (test.MyCalcTest) ... ok
test_substract (test.MyCalcTest) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

$ python test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

2. Test Fixture

테스트 시나리오에 따라
테스트 전에 테스트를 위한 사전 준비 작업을 할 필요가 있습니다.
또한 테스트가 끝난 후
테스트를 하기 위해 만든 리소스들을 정리(clean up)를 해야하는 경우도 있습니다.

unittest는
사전 준비 작업을 위해 setUp() 이라는 메서드를
clean up 처리를 위해 tearDown() 이라는 메서드를 제공합니다.

이러한 기능들을 Test Fixture라 하며,
Fixture는 각각의 테스트 메서드가 실행되기 전과 후에 매번 실행됩니다.

import unittest

class MyCalcTest(unittest.TestCase):
    def setUp(self):
        print("1. Executing the setUp method")
        self.fixture = { 'a' : 1 }

    def tearDown(self):
        print("3. Executing the tearDown method")
        self.fixture = None

    def test_fixture(self):
        print("2. Executing the test_fixture method")
        self.assertEqual(self.fixture['a'], 1)
> python -m unittest --v
test_fixture (test_my_calc.MyCalcTest) ... 
1. Executing the setUp method
2. Executing the text_fixture method
3. Executing the tearDown method
ok

3. Django Unittest

아래 링크들을 번역, 수정해가면서 포스팅하겠습니다.

Writing and running tests
Testing tools

Writing tests

Django 도 python의 unittest 라이브러리를 사용해서 테스트 하면 됩니다.
django.test.TestCase는 unittest의 subclass입니다.

만약 test가 model을 만들거나 수정하는 등 database에 query한다면
test case를 django.test.TestCase의 subclass로 만드는 것이 좋습니다.

from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
    def setUp(self):
        Animal.objects.create(name="lion", sound="roar")
        Animal.objects.create(name="cat", sound="meow")

    def test_animals_can_speak(self):
        """Animals that can speak are correctly identified"""
        lion = Animal.objects.get(name="lion")
        cat = Animal.objects.get(name="cat")
        self.assertEqual(lion.speak(), 'The lion says "roar"')
        self.assertEqual(cat.speak(), 'The cat says "meow"')

tests를 수행하면 test utility는
이름이 "test"로 시작하는 모든 파일에서 모든 test case들을 찾습니다.
그리고 자동적으로 test를 실행합니다.
(실제로는 test case의 test suite을 만들고 그 suite을 실행합니다.)

tests.py 를 만들었다면 test commands를 이용해 실행합니다.

$ ./manage.py test
# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests

# Run all the tests found within the 'animals' package
$ ./manage.py test animals

# Run just one test case
$ ./manage.py test animals.tests.AnimalTestCase

# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak

Testing Tools

1. The test client

test client는 dummy Web browser처럼 행동하는 Python class입니다.
우리가 작성한 view를 테스트할 수 있습니다.

test client를 이용해 할 수 있는 것들은 여러가지가 있습니다.
그 중 두 가지는 다음과 같습니다.

  1. URL에 GET, POST request를 simulate하고 response를 확인할 수 있습니다.
  2. redirect chain을 볼 수 있으며 각 단계에서 URL과 status code를 체크할 수 있습니다.

Overview and a quick example

test client를 사용하기 위해
django.test.Client를 인스턴스화(instantiate)하고
Web Page를 호출하겠습니다.

>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
b'<!DOCTYPE html...'

web page를 호출할 때, 전체 domain이 아니라 URL의 path만 적어줍니다.

>>> c.get('/login/')

아래와 같이 적지 않습니다.

>>> c.get('https://www.example.com/login/')
profile
devzunky@gmail.com

0개의 댓글