단위 테스트 (unit test) : 개별 함수나 메서드 같은 코드의 가장 작은 단위가 예상대로 동작하는지 검증하는 테스트.
- Python 에서 unittest 모듈을 이용해서 단위 테스트를 작성하고 실행할 수 있음
import unittest # 모듈 import
def add(x, y): # 더하는 함수
return x + y
class TestAdd(unittest.TestCase): # 단위 테스트
def test_add(self):
self.assertEqual(add(1, 2), 3) # add(1,2)가 3과 같은지 확인
if __name__ == '__main__':
unittest.main()
# 결과가 OK로 나옴
import unittest
def add(x, y):
return x + y
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(10, 2), 13)
self.assertEqual(add(10, 20), 31)
if __name__ == '__main__':
unittest.main()
# 결과가 Failed로 나옴. 에러가 여러개 있어도 하나만 출력
unittest의 다양한 메서드
import unittest
class TestAdd(unittest.TestCase):
def test_add(self):
print(dir(self)) # 이걸로 어떤 메서드가 있는지 확인
self.assertEqual(1 + 2, 3) # 같은지 판별
self.assertTrue(10 == 10) # True인지 판별
self.assertFalse(1 == 10) # False인지 판별
self.assertGreater(10, 1) # 앞에 것이 뒤에 것보다 큰지
self.assertLess(1, 10) # 앞에 것이 뒤에 것보다 작은지
self.assertIn(1, [1, 2, 3, 4, 5]) # 포함하고 있는지
self.assertIsInstance('a', str) # 인스턴스인지
if __name__ == '__main__':
unittest.main()
여러가지 함수를 만들어서 test 해보기
import unittest
# 구현한 함수
def add(x, y):
return x + y
def sub(x, y):
return x - y
def mul(x, y):
return x * y
# 테스트 코드
class TestAdd(unittest.TestCase):
def test_add(self):
print('더하기 테스트')
self.assertEqual(add(1, 2), 3)
def test_sub(self):
print('빼기 테스트')
self.assertEqual(sub(3, 1), 2)
def test_mul(self):
print('곱하기 테스트')
self.assertEqual(mul(3, 4), 12)
def donghu(self):
'''
테스트 이름을 마음대로 정할 수 있는지 체크
'test_'로 시작하지 않으면 테스트로 인식하지 않음
'''
self.assertEqual(5, 4)
def test_donghu(self):
'''
테스트 이름을 마음대로 정할 수 있는지 체크
'''
self.assertEqual(5, 5)
if __name__ == '__main__':
unittest.main()
TDD : 코드를 작성하기 전 테스트를 먼저 작성하고 그 테스트를 통과하도록 코드를 구현하는 개발 방법론
- 코드의 품질 향상시키고 버그를 줄이고, 빠르게 배포 가능
- 개발자는 요구사항 명세에 대해 보다 잘 이해할 수 있으며, SW가 원하는대로 동작하는지 확인 가능
Django TDD
각 APP의 tests.py 파일에 테스트 코드를 작성하고, python manage.py test 명령어로 테스트
blog / tests.py
from django.test import TestCase
class Test(TestCase):
def test_something(self):
self.assertEqual(True, True)
# python manage.py test로 실행하면 OK 출력
blog / tests.py
from django.test import TestCase
class Test(TestCase):
def test_something_one(self):
self.assertEqual(True, False)
def test_something_two(self):
self.assertEqual(True, True)
# python manage.py test blog.tests.Test.test_someting_one 으로 지정해서 테스트 가능
# Failed 출력
기본 세팅
blog / tests.py
from django.test import TestCase, Client
from bs4 import BeautifulSoup
from .models import Post
class Test(TestCase):
def setUp(self):
# 가상의 client를 만들어서 사용. 이때 DB는 비어있는 채로 시작
self.client = Client()
# setUp()에서는 주로 테스트를 진행하기 전 아래와 같이 데이터를 생성
# self.post_001 = Post.objects.create(
# title='첫 번째 포스트입니다.',
# content='Hello World. We are the world.',
# )
def test_name(self):
pass
테스트 코드 작성 예시
blog / tests.py
from django.test import TestCase, Client
from bs4 import BeautifulSoup
from .models import Post
from accounts.models import User
class Test(TestCase):
def setUp(self):
'''
테스트를 할 때에는 DB가 초기화 되어 있다고 가정하고,
client도 새로 생성하여 테스트를 진행.
'''
print('-- blog app 테스트 시작 --')
self.client = Client() # Client 새로 생성
self.user_donghu = User.objects.create_user( # 유저 생성
username='donghu',
password='nopassword'
)
def test_post_list(self):
post_001 = Post.objects.create(
title = '첫 번째 포스트입니다.',
content = 'Hello World. We are the world.',
author = self.user_donghu,
)
post_002 = Post.objects.create(
title = '두 번째 포스트입니다.',
content = 'Hello World. We are the world.',
author = self.user_donghu,
)
print('-- 1차 테스트 시작 --')
# 테스트 목적 또는 시너리오, 기타 설명등을 주석으로 작성
print('-- 접속 확인 --')
# 1. 접속
# 1.1 포스트 목록 페이지를 가져옴
response = self.client.get('/blog/') # '/blog/'의 response를 가져옴
self.assertEqual(response.status_code, 200) # response가 정상연결(200)인지 확인
# 1.2 정상 접속이 되면 페이지 타이틀에 'Blog'라는 문구 출력
# self.assertTemplateUsed(response, 'blog/post_list.html') # response의 template 파일 확인 가능
soup = BeautifulSoup(response.content, 'html.parser') # html 문서 파싱
self.assertEqual(soup.title.text, 'Blog') # title의 text가 'Blog'인지 확인
print('-- 상속 확인 --')
# 2. 상속
# 2.1 페이지 상속이 제대로 되었다면 nav태그가 있고, footer태그가 있어야 함
# 2.2 nav태그 내부에는 Home, About, Blog라는 문구(메뉴)가 있어야 함
navbar = soup.nav
self.assertIn('Home', navbar.text) # navbar에 'Home'이 있는지 확인
self.assertIn('About', navbar.text)
self.assertIn('Blog', navbar.text)
# footer = soup.footer
# self.assertIn('Instagram', footer.text)
# self.assertIn('Facebook', footer.text)
# self.assertIn('Twitter', footer.text)
print('-- 포스트 목록 확인 --')
# 3. 포스트 목록
# 3.1 포스트 목록이 하나도 없다면 '아직 게시물이 없습니다.'라는 문구가 나와야 함
# 3.2 포스트가 2개 있다면, 포스트의 개수만큼 h2태그가 있어야 함
if Post.objects.count() == 0: # Post의 개수가 0개면
print('게시물이 없는 경우')
self.assertIn('아직 게시물이 없습니다.', soup.body.text)
else:
print('게시물이 있는 경우')
print(len(soup.body.select('h2'))) # h2의 개수
self.assertGreater(len(soup.body.select('h2')), 1) # h2의 개수가 1보다 큰지 확인
print('-- 포스트 내용 확인 --')
# 4. 포스트 내용
# 4.1 포스트가 1개 있다면 해당 포스트의 제목(title)이 포스트 영역에 있어야 함
# 4.2 포스트가 1개 있다면 해당 포스트의 작성자(author)가 포스트 영역에 있어야 함
# 4.3 포스트가 1개 있다면 해당 포스트의 내용(content)이 포스트 영역에 있어야 함
# main_area = soup.find('div', id='main') # id가 'main'인 div를 선택
# self.assertIn(self.post_001.title, main_area.text) # post_001의 title이 main_area의 text에 있는지 확인
def test_post_detail(self):
post_001 = Post.objects.create(
title = '첫 번째 포스트입니다.',
content = 'Hello World. We are the world.',
author = self.user_donghu,
)
# 1. 접속
# 1.1 포스트 목록 페이지를 가져옴
response = self.client.get('/blog/1/')
self.assertEqual(response.status_code, 200)
# 1.2 정상 접속이 되면 페이지 타이틀에 'Document'라는 문구출력
# self.assertTemplateUsed(response, 'blog/post_list.html')
soup = BeautifulSoup(response.content, 'html.parser')
self.assertEqual(soup.title.text, 'Document')
print('-- 상속 확인 --')
# 2. 상속
# 2.1 페이지 상속이 제대로 되었다면 nav태그가 있고, footer태그가 있어야 함
# 2.2 nav태그 내부에는 Home, About, Blog라는 문구(메뉴)가 있어야 함
navbar = soup.nav
self.assertIn('Home', navbar.text)
self.assertIn('About', navbar.text)
self.assertIn('Blog', navbar.text)
# 3. 포스트 내용
# 3.1 포스트가 1개 있다면 해당 포스트의 제목(title)이 포스트 영역에 있어야 함
self.assertIn(post_001.title, soup.body.text)
# 3.2 포스트가 1개 있다면 해당 포스트의 내용(content)이 포스트 영역에 있어야 함
self.assertIn(post_001.content, soup.body.text)
# 3.3 포스트가 1개 있다면 해당 포스트의 작성자(author)가 포스트 영역에 있어야 함
self.assertIn(post_001.author.username, soup.body.text)
'Django' 카테고리의 다른 글
Django 프로젝트(1) - Hot🔥Deal Blog (0) | 2023.11.08 |
---|---|
Django와 SQLite3 (0) | 2023.10.23 |
Django 실습(9) 동영상 CRUD 구현하기 (0) | 2023.10.20 |
Django 실습(8) RDB(관계형 데이터베이스) 만들어보기 (2) | 2023.10.17 |
Django 템플릿 필터 (1) | 2023.10.17 |