TestCase
: unittest 프레임 워크의 테스트 조직의 기본 단위
Fixture
: 테스트를 진행할 때 필요한 테스트용 데이터 혹은 설정 등을 이야기한다. 주로 테스트가 실행되기 전이나 후에 생긴다.
assertion
: unittest에서 테스트 하는 부분이 제대로 됐는지를 확인하는 부분, assertion이 실패하면 테스트도 실패한다.
import unittest
class MyCalcTest(unittest.TestCase):
def test_add(self)
assertEqual, assertTrue, assertRaises, assertRegex
등 다양한 assert메소드들을 사용할 수 있다.def test_add(self):
c = myCalc.add(20, 10)
self.assertEqual(c, 30)
# mycalc.py
def add(a, b):
return a + b
def substract(a, b):
return a - b
# tests.py
import unittest
import mycalc
class MyCalcTest(unittest.TestCase):
def test_add(self):
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()
> python -m unittest --v
test_add (test_my_calc.MyCalcTest) ... ok
test_substract (test_my_calc.MyCalcTest) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
테스트 시나리오에 따라 어떤 경우는 테스트 전에 테스트를 위한 사전 준비 작업을 할 필요가 있습니다. 또한 테스트가 끝난 후 테스트를 하기 위해 만든 리소스들을 정리(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
setUp()
: test(method) 마다 불려서 test데이터셋을 만들어 준다.
setUpTestData()
: TestCase(class) 한 개마다 초기 데이터 test 데이터를 만들어준다.
-> 효율이 더 좋다.
앱 생성 시에 항상 함께 생성되는 tests.py
을 통해 test를 진행합니다.
Django는 기본적으로 unittest를 사용하기 때문에 TestCase 클래스와 테스트를 위한 Client() 객체를 제공합니다.
Client()
Python class인 test client는 views를 테스트하도록 도와주는 가짜 웹 브라우저로 작동한다.
-> Client를 사용하면 서버가 실행되지 않고 있는 상황에서도 프론트의 요청 없이 백엔드가 직접 views.py를 실험할 수 있다.
-> GET, POST requests를 보내줄 수 있고, redirect나 status code도 확인할 수 있다.
# planets/tests.py
from django.test import TestCase, Client
from users.models import User
from planets.models import Accomodation, Planet, PlanetImage, PlanetTheme, Galaxy
class PlanetListTest(TestCase):
@classmethod
def setUpTestData(cls):
User.objects.create(
id = 1,
name = '박건규',
password = '',
email = '박건규@박건규.com',
kakao_id = 123456789111
)
Galaxy.objects.bulk_create([
Galaxy(
id = 1,
name = '우리은하'
),
Galaxy(
id = 2,
name = '가람우주'
)
])
PlanetTheme.objects.bulk_create([
PlanetTheme(
id = 1,
name = '제일 이쁘다'
),
PlanetTheme(
id = 2,
name = '가람테마'
)
])
...
def tearDown(self):
User.objects.all().delete()
Galaxy.objects.all().delete()
PlanetTheme.objects.all().delete()
Planet.objects.all().delete()
PlanetImage.objects.all().delete()
Accomodation.objects.all().delete()
def test_success_planetlistview_get(self):
client = Client()
response = client.get( # 요청보내는 method
'/planets' # 요청보내는 urls 주소
)
self.assertEqual(response.status_code, 200) # status_code 동일한지 확인
self.assertEqual(response.json(), { # json응답이 동일한지 확인
'planets_list':[{
'id' : 1,
'name' : '이쁜행성',
'thumbnail' : 'testurl/testurl/test',
'galaxy' : '우리은하',
'theme' : '제일 이쁘다',
'image' : ['testurl/testurl/test'],
'accomodation_info' :[{
'min_of_people' : 2,
'max_of_people' : 4,
'price' : '2500000.00'
}]
},
{
'id' : 2,
'name' : '가람별2',
'thumbnail' : 'http://urls2',
'galaxy' : '가람우주',
'theme' : '가람테마',
'image' : ['urls2'],
'accomodation_info' :[{
'min_of_people' : 4,
'max_of_people' : 8,
'price' : '200000.00'
}]
}]
})
def test_success_planetlistview_get_filter(self):
client = Client()
response = client.get(
'/planets?galaxy=2&theme=2&people=5'
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), {
'planets_list':[{
'id' : 2,
'name' : '가람별2',
'thumbnail' : 'http://urls2',
'galaxy' : '가람우주',
'theme' : '가람테마',
'image' : ['urls2'],
'accomodation_info' :[{
'min_of_people' : 4,
'max_of_people' : 8,
'price' : '200000.00'
}]
}]
})
...
def test_fail_planetlistview_get_invalid_date(self):
client = Client()
response = client.get(
'/planets?check-in=2022-03-19&check-out=2022-03-18'
)
self.assertEqual(response.status_code, 400) # 에러코드 동일한지 확인
# bookings/tests.py
import jwt, json
from django.test import TestCase, Client
from my_settings import SECRET_KEY, ALGORITHM
from planets.models import Planet, Accomodation, Galaxy, PlanetTheme
from bookings.models import BookingStatus, Booking
from users.models import User
class BookingTest(TestCase):
@classmethod
def setUpTestData(cls):
User.objects.create(
id = 1,
name = '가람',
email = 'kimkrh@naver.com',
kakao_id = 1234
)
...
def tearDown(self):
User.objects.all().delete()
Galaxy.objects.all().delete()
PlanetTheme.objects.all().delete()
Planet.objects.all().delete()
Accomodation.objects.all().delete()
BookingStatus.objects.all().delete()
Booking.objects.all().delete()
def test_success_bookingview_post(self): # test_success 또는 test_fail로 시작하는 것이 보기 좋다.
token = jwt.encode({'id':1}, SECRET_KEY, ALGORITHM) # 임의로 토큰 생성 (Mock)
client = Client()
headers = {'HTTP_Authorization':token} # 헤더에 임의로 생성한 토큰 삽입 -> 로그인 데코레이터 통과
booking = { # body로 보낼 내용
'booking_number' : 1,
'start_date' : '2022-03-22',
'end_date' : '2022-03-23',
'number-of-adults' : 1,
'number-of-children' : 1,
'user_request' : '테스트',
'total_price' : 10000,
'planet_id' : 1,
'accomodation_id' : 1
}
response = client.post( # 요청보내는 method
'/bookings', # 요청보내는 urls 주소
json.dumps(booking), # 요청보낼때 보내는 body
content_type='application/json', # body content_type
**headers # 헤더확인
)
booking_number = Booking.objects.get(id=2).booking_number # 생성된 uuid를 확인하기 위함
self.assertEqual(response.status_code, 201) # status_code 확인
self.assertEqual(response.json(), { # json 응답 확인
'result':{
'booking_id' : 2,
'booking_number' : str(booking_number)
}
})