[django] 테스트 코드 작성하기

dhleeone·2022년 4월 27일
0

지금까지 API 테스트는 Postman을 통해 진행했었다. Postman은 좋은 툴이지만 하나 하나 send 버튼을 누르며 테스트를 해야하는 불편함이 있었다.
하지만 Test 코드를 작성하면 한줄의 명령으로 모든 테스트 케이스를 한번에 처리할 수 있다는 큰 장점이 있다.

APITestCase 사용하기

drf의 APITestCase를 상속받아서 클래스로 test 케이스를 만들 수 있다.

# tests.py

from rest_framework.test import APITestCase
from rest_framework.views import status

from django.shortcuts import resolve_url
from django.urls import reverse
from ..models import *

class PhoneVerificationTestCase(APITestCase):
    def setUp(self):
        self.url_1 = '/accounts/verification'
        self.url_2 = reverse('accounts:verification')
        self.data = {"phone": "01012345678"}

    def test_post_phone_number_success(self):
        response = self.client.post(self.url_1, data=self.data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_post_phone_number_string_error(self):
        data = {"phone": "010123456abc"}
        response = self.client.post(self.url_2, data=data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

setUp 작성하기

  • 먼저 setUp 메서드에서 기본적으로 test에 필요한 url, 공통적으로 body에 담길 data 등을 지정할 수 있다.

  • url에서 만약 url name을 사용하려면 위 코드의 url_2와 같이 reverse 혹은 resolve_url 사용할 수 있다.

테스트 케이스 만들기

  • 테스트 함수명의 앞에는 test가 있어야 테스트가 실행된다.

  • self.client 뒤에 http 메소드(위에서는 post)를 써주고 인자로 (url, data, format)을 넣으면 이에 대한 응답이 response에 담기게 된다.

  • self.assertEqual는 테스트의 응답이 기대하는 응답과 일치하는지 확인해준다. 위 코드에서는 인자로 response의 상태코드, 기대하는 응답의 상태 코드를 넣어주었다.

  • python manage.py test 명령으로 테스트가 실행된다.
    첫번째 테이스 케이스에서 201 상태 코드를 반환하면 테스트에 통과하게 되고 다른 상태 코드를 반환하면 fail이 뜨게 된다.


Factory 및 Faker 사용하기

factory를 사용하면 간편하게 테스트용 임시 데이터를 생성할 수 있으며 다량의 데이터가 필요할 때 더욱 편리하다.

factory-boy 인스톨

pip install factory-boy
factory를 사용하기 위해서 우선 factory-boy를 인스톨한다.

faker 인스톨

pip install faker
무작위 데이터를 생성해주는 faker를 인스톨한다.

factory 코드 작성

# factories.py

import factory
from faker import Faker
from django.contrib.auth.hashers import make_password
from ..models import *

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User

    name = Faker().name()
    nickname = Faker().name()
    email = factory.lazy_attribute(lambda u: f"{u.name.split()[0]}@example.com")
    phone = "01012345678"
    password = make_password("qwer1234")

위 코드를 통해 테스트용 user 인스턴스를 만들 수 있다.

  • factory를 임포트한 뒤, 무작위 데이터를 생성해주는 Faker를 임포트해준다.

  • UserFactory 클래스에 factory.django.DjangoModelFactory를 상속받는다.

  • class Meta에 사용할 모델(여기서는 User)를 지정해준다. (serializer와 유사함)

  • 이제 필드값을 지정해주는데, 이때 이름과 닉네임은 Faker().name()을 통해 무작위로 생성해준다. (이외 이메일의 경우 Faker().email() 등 사용 가능..)

  • factory.lazy_attribute를 통해 위에서 지정한 필드값을 사용할 수 있다.(위 코드에서는 name 값의 첫번째 문자열을 이메일 앞부분으로 사용함)

  • 전화번호와 비밀번호는 직접 지정해주었다.(비밀번호는 make_password로 암호화)

테스트 케이스에서 Factory 사용하기

# tests.py

from .factories import UserFactory
...

class LoginTestCase(APITestCase):
    def setUp(self):
        self.url = '/accounts/login'
        self.user = UserFactory()
    def test_login_success(self):
        data = {
            "email": self.user.email,
            "password": "qwer1234",
        }
        print(self.user)
        response = self.client.post(self.url, data=data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
  • UserFactory를 임포트한 뒤, self.user = UserFactory()를 선언한다. 그러면 해당 테스트용 user 인스턴스로 로그인에 대한 테스트를 수행할 수 있다.

📌 faker를 통해 생성된 name과 email은 다음과 같다.

print(self.user.name)
print(self.user.email)
-----------------------------
Glenn Hunter
Glenn@example.com

만약 Factory를 사용하지 않았다면 로그인 테스트 코드가 다음과 같게 된다.
(setUp에서 테스트용 user 객체를 생성)

class LoginTestCase(APITestCase):
    def setUp(self):
        self.url = '/accounts/login'
        self.user = User.objects.create(
            email="test@example.com",
            nickname="test",
            phone="01012345678"
        )
        self.user.set_password("qwer1234")
        self.user.save()

    def test_login_success(self):
        data = {
            "email": "test@example.com",
            "password": "qwer1234",
        }
        response = self.client.post(self.url, data=data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

factory를 사용하면 테스트 코드가 간결해지고 가독성이 높아지는 것을 느낄 수 있다. (다량의 객체 생성이 필요할 때 효과 up)

profile
하루하루 쌓아가는 개발 지식📦

0개의 댓글