TDD (Test Driven Development)
210729, 210730
TDD๋ ๋ฌด์์ธ๊ฐ?
ํ
์คํธ ์ฃผ๋ ๊ฐ๋ฐ
๊ธฐ์กด ๊ฐ๋ฐ ๋ฐฉ์
๊ตฌํ
์น ๋ธ๋ผ์ฐ์ ๋ก ์ง์ ํ์ธ
์ฑ๊ณต
๊ฐ์ ์ ์ฐพ๊ธฐ
TDD
ํ ์คํธ ์ฝ๋ ์์ฑ
๊ธฐ๋ฅ ๊ตฌํ
๋ฆฌํฉํ ๋ง
TDD๋ฅผ ํ๋ ์ด์
ํ๋ก๊ทธ๋จ์ด ๋ณต์กํด ์ง์๋ก, ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๋๋ง๋ค ๊ธฐ๋ฅ ์ฌ์ด์ ์ฐ๊ด์ฑ์ด ์ปค์ง๋ค
์๋ก์ด ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ๋ ๋ง๋ค ๋ธ๋ผ์ฐ์ ์์ ํ์ธ์ด ์ด๋ ค์์ง๋ค
๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง ๋ชจ๋ฅด๊ณ ๊ฐ๋ฐ์ ํ๋ค๊ฐ, ์ถํ์ ์์ ํ ๋ ๊ฑด๋๋ฆฌ๊ธฐ ์ด๋ ค์
๋ธ๋ก๊ทธ ๋ชฉ๋ก ํ์ด์ง์ ๋ํ ํ
์คํธ ์ฝ๋ ๋ง๋ค๊ธฐ
from django.test import TestCase
# Create your tests here.
class TestView(TestCase):
def test_post_list(self):
self.assertEqual(2, 2)
# 1.1 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง(post list)๋ฅผ ์ฐ๋ค
# 1.2 ์ ์์ ์ผ๋ก ํ์ด์ง๊ฐ ๋ก๋๋๋ค.
# 1.3 ํ์ด์ง์ ํ์ดํ์ Blog๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ์๋ค.
# 1.4 NavBar๊ฐ ์๋ค
# 1.5 Blog, About me๋ผ๋ ๋ฌธ๊ตฌ๊ฐ Nav์ ์๋ค.
# 2.1 ๊ฒ์๋ฌผ์ด ํ๋๋ ์์ ๋
# 2.2 ๋ฉ์ธ ์์ญ์ "์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค" ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋์จ๋ค.
# 3.1 ๋ง์ฝ ๊ฒ์๋ฌผ์ด 2๊ฐ ์๋ฐ๋ฉด,
# 3.2 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์นจํ์ ๋,
# 3.3 ๋ฉ์ธ ์์ญ์ ํฌ์คํธ 2๊ฐ์ ํ์ดํ์ด ์กด์ฌํ๋ค
# 3.4 "์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค" ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ์์ด์ผ ํ๋ค๋ค
์์์ ์ด๋ ๊ฒ ๋ง๋ก ๋ค ์จ๋๋๋ค.
ํผ์์ ๊ฐ๋ฐํ๋๊ฒ ์๋๋ผ ์ฌ๋ฟ์ด ๊ฐ๋ฐํ ๋ ์ด๋ฌํ ๊ณผ์ ์ด ๋์์ด ๋๋ค.
test.py
from django.test import TestCase, Client
from bs4 import BeautifulSoup
from .models import Post
class TestView(TestCase):
def setUp(self):
self.client = Client()
def test_post_list(self):
pass
# 1.1 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง(post list)๋ฅผ ์ฐ๋ค
response = self.client.get('/blog/')
# 1.2 ์ ์์ ์ผ๋ก ํ์ด์ง๊ฐ ๋ก๋๋๋ค.
self.assertEqual(response.status_code, 200)
# 1.3 ํ์ด์ง์ ํ์ดํ์ Blog๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ์๋ค.
soup = BeautifulSoup(response.content, 'html.parser')
self.assertIn('Blog', soup.title.text)
# # 1.4 NavBar๊ฐ ์๋ค
navbar = soup.nav
# # 1.5 Blog, About me๋ผ๋ ๋ฌธ๊ตฌ๊ฐ Nav์ ์๋ค.
self.assertIn('Blog', navbar.text)
self.assertIn('About me', navbar.text)
# 2.1 ๊ฒ์๋ฌผ์ด ํ๋๋ ์์ ๋
self.assertEqual(Post.objects.count(), 0)
# 2.2 ๋ฉ์ธ ์์ญ์ "์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค" ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋์จ๋ค.
main_area = soup.find('div', id='main-area')
self.assertIn('์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค.', main_area.text)
# 3.1 ๋ง์ฝ ๊ฒ์๋ฌผ์ด 2๊ฐ ์๋ค๋ฉด,
post_001 = Post.objects.create(
title='์ฒซ๋ฒ์งธ ํฌ์คํธ ์
๋๋ค.',
content='Hello, World. We are the World.',
)
post_002 = Post.objects.create(
title='๋๋ฒ์งธ ํฌ์คํธ ์
๋๋ค.',
content='์๋
์ฌ๋ฌ๋ถ, ๋๋ ์ฌ๋ฌ๋ถ์ ์ผ๋ถ์ผ.',
)
self.assertEqual(Post.objects.count(), 2)
# 3.2 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์นจํ์ ๋,
response = self.client.get('/blog/')
soup = BeautifulSoup(response.content, 'html.parser')
# 3.3 ๋ฉ์ธ ์์ญ์ ํฌ์คํธ 2๊ฐ์ ํ์ดํ์ด ์กด์ฌํ๋ค
main_area = soup.find('div', id='main-area')
self.assertIn(post_001.title, main_area.text)
self.assertIn(post_002.title, main_area.text)
# 3.4 "์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค" ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ์์ด์ผ ํ๋ค
self.assertNotIn('์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค.', main_area.text)
assertEqual(A, B)
A์ B๊ฐ ๊ฐ์์ผ ํ๋ค. ๊ฐ์ง ์์ผ๋ฉด python manage.py test ์์ ์ค๋ฅ๊ฐ ๋๋ค.
์์์๋ soup.title.text์ 'Blog'๊ฐ ๊ฐ์์ผ ํ๋ค๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ฉด์ ํ๋์ฉ ํ ์คํธ ํ๊ณ ์๋ค
assertIn[assertNotIn](A, B)
A๊ฐ B์์ ํฌํจ๋[์ง ์์]์ด์ผ ํ๋ค๋ผ๋ ์ฝ๋
post_list.html
<div class="col-md-8 col-lg-9" id="main-area">
{% if post_list.exists %}
{% for p in post_list %}
<!-- Blog post-->
<div class="card mb-4">
{% if p.head_image %}
<img class="card-img-top" src="{{ p.head_image.url }}" alt="{{ p.title }}" />
{% else %}
<img class="card-img-top" src="https://picsum.photos/seed/{{ p.id }}/700/400" alt="{{ p.title }}">
{% endif %}
<div class="card-body">
<div class="small text-muted">January 1, 2021</div>
<h2 class="card-title h4">{{ p.title }}</h2>
{% if p.hook_text %}
<h5 class="text-muted"> {{ p.hook_text }} </h5>
{% endif %}
<p class="card-text">{{ p.content | truncatewords:50 }}</p>
<a class="btn btn-primary" href="{{ p.get_absolute_url }}">Read more โ</a>
</div>
<div class="card-footer text-muted">
Posted on {{ p.created_at }} Update at {{ p.updated_at }} by
<a href="#">์์ฑ์๋ช
์ธ ์์น</a>
</div>
</div>
{% endfor %}
{% else %}
<h1>์์ง ๊ฒ์๋ฌผ์ด ์์ต๋๋ค</h1>
{% endif $}
div์
main-area
๋ผ๋ id๋ฅผ ์ถ๊ฐํ๋คpost_list.exists
๋ก post_list๊ฐ ์กด์ฌํ๋์ง์ ๋ํ if๋ฌธ์ ์ถ๊ฐํ๋ค
๋ธ๋ก๊ทธ ์์ธ ํ์ด์ง์ ๋ํ ํ
์คํธ ์ฝ๋ ๋ง๋ค๊ธฐ
tests.py
def test_post_detail(self):
# 1.1 ํฌ์คํธ๊ฐ ํ๋ ์๋ค
# 1.2 ๊ทธ ํฌ์คํธ์ url์ `/blog/1/` ์ด๋ค
# 2. ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์์ธ ํ์ด์ง ํ
์คํธ
# 2.1 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ url๋ก ์ ๊ทผํ๋ฉด ์ ์์ ์ผ๋ก response๊ฐ ์จ๋ค(status code : 200)
# 2.2 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง์ ๋๊ฐ์ ๋ด๋น๊ฒ์ด์
๋ฐ๊ฐ ์๋ค.
# 2.3 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์ ๋ชฉ์ด ์น ๋ธ๋ผ์ฐ์ ํญ ํ์ดํ์ ๋ค์ด์๋ค.
# 2.4 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์ ๋ชฉ์ด ํฌ์คํธ ์์ญ์ ์๋ค.
# 2.5 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์์ฑ์(author)๊ฐ ํฌ์คํธ ์์ญ์ ์๋ค(์์ง ๊ตฌํํ ์ ์์)
# 2.6 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ๋ด์ฉ(content)์ด ํฌ์คํธ ์์ญ์ ์๋ค.
def test_post_detail(self):
# 1.1 ํฌ์คํธ๊ฐ ํ๋ ์๋ค
post_001 = Post.objects.create(
title='์ฒซ๋ฒ์งธ ํฌ์คํธ ์
๋๋ค.',
content='Hello, World. We are the World.',
)
self.assertEqual(Post.objects.count(), 1)
# 1.2 ๊ทธ ํฌ์คํธ์ url์ `/blog/1/` ์ด๋ค
self.assertEqual(post_001.get_absolute_url(), '/blog/1')
# 2. ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์์ธ ํ์ด์ง ํ
์คํธ
# 2.1 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ url๋ก ์ ๊ทผํ๋ฉด ์ ์์ ์ผ๋ก response๊ฐ ์จ๋ค(status code : 200)
response = self.client.get(post_001.get_absolute_url())
self.assertEqual(response.status_code, 200)
soup = BeautifulSoup(response.content, 'html.parser')
# 2.2 ํฌ์คํธ ๋ชฉ๋ก ํ์ด์ง์ ๋๊ฐ์ ๋ด๋น๊ฒ์ด์
๋ฐ๊ฐ ์๋ค.
navbar = soup.nav
self.assertIn('Blog', navbar.text)
self.assertIn('About me', navbar.text)
# 2.3 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์ ๋ชฉ์ด ์น ๋ธ๋ผ์ฐ์ ํญ ํ์ดํ์ ๋ค์ด์๋ค.
self.assertIn(post_001.title, soup.title)
# 2.4 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์ ๋ชฉ์ด ํฌ์คํธ ์์ญ์ ์๋ค.
main_area = soup.find('div', id='main-area')
post_area = main_area.find('div', id='post-area')
self.assertIn(post_001.title, post_area.text)
# 2.5 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ์์ฑ์(author)๊ฐ ํฌ์คํธ ์์ญ์ ์๋ค(์์ง ๊ตฌํํ ์ ์์)
# 2.6 ์ฒซ๋ฒ์งธ ํฌ์คํธ์ ๋ด์ฉ(content)์ด ํฌ์คํธ ์์ญ์ ์๋ค.
self.assertIn(post_001.content, post_area.text)
Last updated
Was this helpful?