장고 REST Framework 이용
장고에서 테스트 하며 개발하는 방법
views,model,settings,urls,html,form
사용자가 url로 장고에 요청
url에 매핑되어 있는 함수가 실행
함수는 연산 후 html 반환
TestCase 할 때는 해당 import 해주어야함
33from django.test import TestCase
tests 패키지에 test_urls.py
from django.test import TestCase
from django.urls import resolve
from board.views import create
class TestUrls(TestCase):
def test_create_url_is_resolved(self):
url = resolve('/board/create') # resolve함수는 urls.py에 있는 해당 url을 찾아서 해당하는 객체를 반환해옴
self.assertEqual(url.func, create)
urls.py
path('board/create', board.views.create),
views.py
from django.shortcuts import render
# Create your views here.
def create(request):
return render(request, 'board/create.html')
터미널에 해당 명령어로 test code 실행 (test가 들어간 것 실행해줌)
python .\manage.py test
특정 test case 실행하고싶으면
python .\manage.py test board.test.test_views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s.TestViews.test_posts.~
from django.contrib.auth.models import User
from django.test import TestCase, Client
class TestUrls(TestCase):
def setUp(self): # 필요한 객체, 데이터를 생성하는 메소드
self.client = Client() # Client객체. 요청을 보낼 수 있게 해줌
self.user = User.objects.create_user(username='user01', password='qwer1234!')
def test_post_create_GET_with_login(self):
self.client.login(username='user01', password='qwer1234!')
response = self.client.get('/board/create')
self.assertEqual(response.status_code, 200) # 정상적으로 받아갔다면 사용자 상태코드는 200이 되어야 함
self.assertTemplateUsed(response, 'board/create.html')
def test_post_create_GET_without_login(self):
# 로그인 페이지가 뜨는 지 확인
response = self.client.get('/board/create')
self.assertEqual(response.status_code, 302) # redirect 시킬때 302가 뜸
# self.assertTemplateUsed(response, 'accounts/login.html')
def test_post_create_POST_without_login(self):
# 로그인 페이지가 뜨는 지 확인
response = self.client.post('/board/create')
self.assertEqual(response.status_code, 302) # redirect 시킬때 302가 뜸
def test_post_create_POST_with_login(self):
self.client.login(username='user01', password='qwer1234!')
response = self.client.post('/board/create', data={'title': 'title3', 'contents': 'contents1'})
post = Post.objects.get(title='title3')
self.assertEqual(post.title, 'title3')
self.assertEqual(response.status_code, 302)
Post Model 생성
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
contents = models.TextField()
writer = models.ForeignKey(User, on_delete=models.CASCADE)
마이그레이션
POST에 대한 CRUD TEST
from django.contrib.auth.models import User
from board.models import Post
from django.test import TestCase
class TestModels(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='user01', password='qwer1234!')
self.post = Post.objects.create(title='title1',contents='contents1',writer=self.user)
def test_post_model_create(self):
post = Post()
post.title = 'title2'
post.contents = 'contents'
post.writer = self.user
post.save()
post = Post.objects.get(title='title2')
self.assertEqual(post.title, 'title2')
def test_post_model_read(self):
post = Post.objects.get(id=1)
self.assertEqual(post.title, 'title1')
def test_post_model_update(self):
# 조회하고 바꾸고, 다시 조회했을 때 바뀐 내용으로 바꿔져있어야 함
post = Post.objects.get(id=1)
post.title = 'title3'
post.save()
post = Post.objects.get(id=1)
self.assertEqual(post.title, 'title3')
def test_post_model_delete(self):
post = Post.objects.get(id=1)
post.delete()
self.assertFalse(Post.objects.filter(id=1).exists())
title 길이가 5 미만이면 에러 메시지 띄우기
test 코드
def test_post_create_POST_with_check_title_length(self):
self.client.login(username='user01', password='qwer1234!')
response = self.client.post('/board/create', data={'title': 'ti', 'contents': 'contents1'})
#self.assertEqual(response.url, '/error')
messages = list(response.context['messages'])
self.assertEqual(len(messages), 1) # 현재 에러 메시지 한개 담겨있어야함
self.assertEqual(str(messages[0]),'제목은 다섯글자 이상이어야 합니다.') # 알맞은 에러 메시지 담겨있어야함
self.assertEqual(response.status_code, 400) # 400으로 바꿔서 온 지 확인
views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
# Create your views here.
from board.forms import PostForm
from board.models import Post
from django.contrib import messages
@login_required(login_url='accounts/login')
def create(request):
if request.method == 'GET':
postForm = PostForm()
context = {'postForm':postForm}
return render(request, 'board/create.html',context)
elif request.method == 'POST':
postForm = PostForm(request.POST)
context = {
'postForm' : postForm,
'has_error' : False
}
post = Post()
post.title = request.POST.get('title')
if len(post.title)<5:
messages.add_message(request, messages.ERROR,"제목은 다섯글자 이상이어야 합니다.") # 에러 메시지 담기, info나 원인같은 등급도 있음
context['has_error']=True # 에러가 있으면 has_error을 False로 만듦
post.contents = request.POST.get('contents')
post.writer = request.user
if context['has_error']:
return render(request, 'board/create.html',context, status=400) # 에러처리(400, 클라이언트 잘못)를 해서 넘김
post.save()
return redirect('/board/read/'+str(post.id))
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{% csrf_token %}
{{ postForm }}
<button>작성</button>
{% if messages %}
{% for message in messages%}
{% if message.tags == 'error' %}
{{ message }}
{% endif %}
{% endfor %}
{% endif %}
</form>
</body>
</html>
class TestUrls(TestCase):
def setUp(self): # 필요한 객체, 데이터를 생성하는 메소드
self.client = Client() # Client객체. 요청을 보낼 수 있게 해줌
self.user01 = User.objects.create_user(username='user01', password='qwer1234!')
self.user02 = User.objects.create_user(username='user02', password='qwer1234!')
self.post = Post.objects.create(title='title1', contents='contents1',writer=self.user01)
def test_post_read_GET_with_writer(self):
self.client.login(username='user01', password='qwer1234!')
response = self.client.get('/board/read/1')
self.assertTemplateUsed(response, 'board/read.html')
self.assertInHTML('<button>수정</button>', response.content.decode()) # 해당글자가 HTML에 있는지
def test_post_read_GET_without_writer(self):
self.client.login(username='user02', password='qwer1234!')
response = self.client.get('/board/read/1')
self.assertTemplateUsed(response, 'board/read.html')
self.assertNotIn('<button>수정</button>',response.content.decode())
def test_post_read_GET_with_other_writer(self):
response = self.client.get('/board/read/1')
self.assertTemplateUsed(response, 'board/read.html')
self.assertNotIn('<button>수정</button>', response.content.decode())
나머지 views나 templates은 writer면 수정삭제 뜨게 하는 코드로
셀레니움 - 가벼운 경량 프로그램사용 보통 ChromeDriver 사용
ChromeDriver 설치 후 C드라이브에 풀기
pip install selenium
웹페이지 띄우고 간단 조작
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome('c:/chromedriver.exe')
driver.get('https://nid.naver.com/nidlogin.login')
id_input_tag = driver.find_element(By.ID, 'id')
id_input_tag.send_keys('qwer1234')
id_input_tag = driver.find_element(By.ID, 'pw')
id_input_tag.send_keys('qqqqq')
time.sleep(4)
login_btn_tag = driver.find_element(By.CLASS_NAME, 'btn_login ')
login_btn_tag.click()
# pw_input_tag.send_keys(Keys.RETURN) # 엔터 입력
#driver.quit() # x 해도 백그라운드에 남아있을 수 있으니 해당 명령어로 종료해주어야 함
특정 태그 찾을 때
네이버 - 엔터의 글자 가져오기
import time
from selenium import webdriver
from selenium.webdriver import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Chrome('c:/chromedriver.exe')
driver.get('https://www.naver.com/')
enter_btn = driver.find_element(By.XPATH, '/html/body/div[2]/div[3]/div[2]/div[3]/div/div[1]/div[2]/div/div/ul/li[1]/a')
enter_btn.click()
text_tag = driver.find_element(By.XPATH,'/html/body/div[2]/div[3]/div[2]/div[3]/div/div[2]/div[1]/div[1]/div/a[2]/strong')
print(text_tag.text)
#driver.quit() # x 해도 백그라운드에 남아있을 수 있으니 해당 명령어로 종료해주어야 함