Django

파이썬 장고 실무 심화 5주차_테스트코드 TDD

끈끈 2023. 4. 21. 20:37

 

테스트 코드

 

시간 낭비, 복잡도 증가, 허점을 보완하기 위해

 

작성한 코드들이 원하는 값을 내놓는지 확인하는 코드

 

 

테스트 주도 개발, TDD

(Test-Driven Development)

 

먼저 자동화된 테스트 코드를 작성한 후

 

테스트를 통과하기 위한 코드를 개발하는 방식의 개발 방식

 


 

python manage.py test
python manage.py test <앱이름> : 앱에서 작성한 하나의 test만 실행하고 싶을 때

from django.test import TestCase

 

 

 

tests.py 생성

 

test

 

https://www.django-rest-framework.org/api-guide/testing/

 

Testing - Django REST framework

 

www.django-rest-framework.org

 

 

https://docs.djangoproject.com/en/4.2/topics/testing/advanced/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 


 

Faker

 

작성을 편리하게 해주는 라이브러리

 

자동으로 랜덤한 데이터를 생성해준다

 

pip install Faker

 

from faker import Faker

fake = Faker()
fake = Faker("ko_KR") # 한국어 (name만 가능)

fake.name()
fake.first_name()
fake.last_name()
fake.word() # 랜덤 단어 (비밀번호)
fake.sentence() # 랜덤 문장 (게시글 제목)
fake.text() # 랜덤 글 (게시글 내용)

 

https://pypi.org/project/Faker/

 

Faker

Faker is a Python package that generates fake data for you.

pypi.org

 


 

get_absolute_url

 

from django.urls import reverse


class Article(models.Model):
 
    
    def get_absolute_url(self):
        return reverse("article_detail_view", kwargs={"pk": self.pk})

 

https://docs.djangoproject.com/en/4.2/ref/models/instances/#get-absolute-url

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 


 

아래는 강의 자료와 달라서 꽤나 짜증났던 부분..!

 

users > models.py:

from django.urls import reverse


class User(AbstractBaseUser):
    
    
    def get_absolute_url(user_id):
        return reverse("profile_view", kwargs={"user_id": user_id})

 

users > tests.py:

from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import User


class UserRegistrationTest(APITestCase):
    def test_registration(self):
        url = reverse("user_view")  # urls의 name을 가져옴
        user_data = {
            "username": "john",
            "fullname": "테스터",
            "email": "test@testuser.com",
            "password": "johnpassword",
        }
        response = self.client.post(url, user_data)
        self.assertEqual(response.status_code, 201)


class LoginUserTest(APITestCase):
    def setUp(self):
        self.data = {"email": "test@testuser.com", "password": "johnpassword"}
        self.user = User.objects.create_user(
            'test@testuser.com', 'johnpassword')

    def test_login(self):
        response = self.client.post(
            reverse('token_obtain_pair'), data=self.data)
        self.assertEqual(response.status_code, 200)

    def test_get_user_data(self):
        url = User.get_absolute_url(user_id=self.user.id)
        access_token = self.client.post(
            reverse('token_obtain_pair'), data=self.data).data["access"]
        response = self.client.get(
            path=url,
            HTTP_AUTHORIZATION=f"Bearer {access_token}"
        )
        self.assertEqual(response.data["email"], self.data["email"])

 

"Reverse for '/users/1/' not found"

 

test_get_user_date의 self.cliendt.get에서 자꾸 에러가 났는데

 

path=reverse(url)에서 path=url로 바꿔주니 성공!

 

>>> reverse('뷰 함수')인데 get_absolute_url() 메서드에서 반환하는 URL은 '/users/1/'의 형식이었기 때문

 

 

articles > models.py:

from django.urls import reverse


class Article(models.Model):
   

    def get_absolute_url(self):
        return reverse("article_detail_view", kwargs={"article_id": self.id})

 

articles > tests.py:

from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from articles.models import Article
from articles.serializers import ArticleSerializer
from users.models import User
from faker import Faker

# 이미지 업로드
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from PIL import Image
import tempfile


def get_temporary_image(temp_file):
    size = (200, 200)
    color = (255, 0, 0, 0)
    image = Image.new("RGBA", size, color)
    image.save(temp_file, 'png')
    return temp_file


class ArticleCreateTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user_data = {'email': 'john', 'password': 'johnpassword'}
        cls.article_data = {'title': 'title', 'content': 'content'}
        cls.user = User.objects.create_user('john', 'johnpassword')

    def setUp(self):
        self.access_token = self.client.post(
            reverse('token_obtain_pair'), self.user_data).data['access']
        print(self.access_token)

    def test_fail_if_not_logged_in(self):
        url = reverse("article_view")
        response = self.client.post(url, self.article_data)
        self.assertEqual(response.status_code, 401)

    def test_create_article(self):
        response = self.client.post(
            path=reverse("article_view"),
            data=self.article_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}"
        )
        self.assertEqual(response.status_code, 200)
        print(response.data)

    def test_create_article_with_image(self):
        # 임시 이미지 파일 생성
        temp_file = tempfile.NamedTemporaryFile()
        temp_file.name = "image.png"
        image_file = get_temporary_image(temp_file)
        image_file.seek(0)
        # setUpTestData의 article_data에 추가
        self.article_data["image"] = image_file

        # 전송
        response = self.client.post(
            path=reverse("article_view"),
            data=encode_multipart(data=self.article_data, boundary=BOUNDARY),
            content_type=MULTIPART_CONTENT,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}"
        )
        self.assertEqual(response.status_code, 200)


class ArticleReadTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.faker = Faker()
        cls.articles = []
        for i in range(10):
            cls.user = User.objects.create_user(
                cls.faker.name(), cls.faker.word())
            cls.articles.append(Article.objects.create(
                title=cls.faker.sentence(), content=cls.faker.text(), user=cls.user))

    def test_get_article(self):
        for article in self.articles:
            url = article.get_absolute_url()
            response = self.client.get(url)
            serializer = ArticleSerializer(article).data
            for key, value in serializer.items():
                self.assertEqual(response.data[key], value)
                print(key, value)