난생 처음 해 보는 unit test라 너무 힘들었지만..
결실을 맺었다😭
디버깅 하는데 몇 시간을 소비한 것인가...
from django.urls import path, include
urlpatterns = [
path('users', include('users.urls')),
]
from django.urls import path
from users.views import KakaoSigninView
urlpatterns = [
path('/signin/kakao', KakaoSigninView.as_view())
]
users
에 kakao_id
가 있지 않고 두 개의 테이블이 더 생성되어 외부 키로 연결되어 있다.platforms
에 serial_number
가 있으며 이것이 해당 플랫폼의 고유 id
를 뜻한다.social_networks
에 kakao
나 naver
와 같이 소셜 로그인 기능을 지원하는 소셜 네트워크가 있다.password
가 null=True
인 이유는 소셜 로그인을 하였을 때 비밀번호가 저장되지 않기 때문이다.profile_image_url
에 default 값을 넣어 둔 것은 사용자가 프로필 이미지를 선택 사항으로 동의하지 않았을 때를 위해 넣어두었다.from django.db import models
from places.models import Place
from core.models import TimeStampModel
class User(TimeStampModel):
email = models.CharField(max_length=80, null=True, unique=True)
password = models.CharField(max_length=200, null=True)
nickname = models.CharField(max_length=80, null=True)
profile_image_url = models.CharField(max_length=1000, default='https://cdn-icons-png.flaticon.com/512/1450/1450252.png')
date_of_birth = models.DateField(null=True)
platform = models.ForeignKey('Platform', on_delete=models.CASCADE, null=True)
class Meta:
db_table = 'users'
class WishList(TimeStampModel):
place = models.ForeignKey(Place, on_delete=models.CASCADE)
user = models.ForeignKey('User', on_delete=models.CASCADE)
class Meta:
db_table = 'wish_lists'
class Platform(models.Model):
serial_number = models.BigIntegerField()
social_network = models.ForeignKey('SocialNetwork', on_delete=models.CASCADE)
class Meta:
db_table = 'platforms'
class SocialNetwork(models.Model):
name = models.CharField(max_length=100, unique=True)
class Meta:
db_table = 'social_networks'
get_or_create
를 통해 없을 경우 create
있을 경우 get
을 이용한다.User.objects.get_or_create
조건에 dafaults
만 넣어두니 아래와 같은 에러가 발생하였다.======================================================================
FAIL: test_success_kakao_signup (users.tests.KakaoSigninTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/taekwon/miniconda3/envs/bob_morgan/lib/python3.9/unittest/mock.py", line 1336, in patched
return func(*newargs, **newkeywargs)
File "/Users/taekwon/Desktop/bob_morgan/users/tests.py", line 63, in test_success_kakao_signup
self.assertEqual(response.status_code, 201)
AssertionError: 200 != 201
----------------------------------------------------------------------
status code 201
이 떠야 하는데 get
만 하니200
이 뜨는 것이다.
access_token
에서 인코딩 하는 아이디를 platform
에서 user.id
로 바꾸었다.import jwt, requests
from django.http import JsonResponse
from django.views import View
from django.conf import settings
from users.models import User, SocialNetwork, Platform
class KakaoSigninView(View):
def get(self, request):
try:
kakao_token = request.headers.get('Authorization')
KAKAO_URL = 'https://kapi.kakao.com/v2/user/me'
headers = {'Authorization': f'Bearer {kakao_token}'}
response = requests.get(KAKAO_URL, headers=headers, timeout=3)
kakao_user = response.json()
kakao_id = kakao_user['id']
kakao_nickname = kakao_user['kakao_account']['profile']['nickname']
kakao_email = kakao_user['kakao_account']['email']
profile_image_url = kakao_user['kakao_account']['profile']['profile_image_url']
kakao = SocialNetwork.objects.get(name='kakao').id
platform, is_created = Platform.objects.get_or_create(
serial_number = kakao_id,
social_network_id = kakao
)
platform, is_created = User.objects.get_or_create(
defaults = {
'platform_id' : platform.id,
'nickname' : kakao_nickname,
'email' : kakao_email,
'profile_image_url' : profile_image_url,
}
)
access_token = jwt.encode({'id': platform.id}, settings.SECRET_KEY, settings.ALGORITHM)
if is_created:
return JsonResponse({'message' : 'ACCOUNT_CREATED', 'access_token': access_token}, status=201)
else:
return JsonResponse({'message' : 'SIGN_IN_SUCCESS', 'access_token': access_token}, status=200)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
import jwt, requests
from django.http import JsonResponse
from django.views import View
from django.conf import settings
from users.models import User, SocialNetwork, Platform
class KakaoSigninView(View):
def get(self, request):
try:
kakao_token = request.headers.get('Authorization')
KAKAO_URL = 'https://kapi.kakao.com/v2/user/me'
headers = {'Authorization': f'Bearer {kakao_token}'}
response = requests.get(KAKAO_URL, headers=headers, timeout=3)
kakao_user = response.json()
kakao_id = kakao_user['id']
kakao_nickname = kakao_user['kakao_account']['profile']['nickname']
kakao_email = kakao_user['kakao_account']['email']
profile_image_url = kakao_user['kakao_account']['profile']['profile_image_url']
kakao = SocialNetwork.objects.get(name='kakao').id
platform, is_created = Platform.objects.get_or_create(
serial_number = kakao_id,
social_network_id = kakao
)
user, is_created = User.objects.get_or_create(
platform = platform,
defaults = {
'platform' : platform,
'nickname' : kakao_nickname,
'email' : kakao_email,
'profile_image_url' : profile_image_url,
}
)
access_token = jwt.encode({'id': user.id}, settings.SECRET_KEY, settings.ALGORITHM)
if is_created:
return JsonResponse({'message' : 'ACCOUNT_CREATED', 'access_token': access_token}, status=201)
else:
return JsonResponse({'message' : 'SIGN_IN_SUCCESS', 'access_token': access_token}, status=200)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
import jwt
from django.test import Client, TestCase
from django.conf import settings
from unittest.mock import patch, MagicMock
from users.models import Platform, User, SocialNetwork
class KakaoSigninTest(TestCase):
def setUp(self):
SocialNetwork.objects.create(
id = 1,
name = 'kakao',
)
Platform.objects.create(
id = 123456,
serial_number = 987654,
social_network_id = SocialNetwork.objects.get(name='kakao').id,
)
User.objects.create(
id = 5,
email = 'test@kakao.com',
nickname = 'test',
platform_id = Platform.objects.get(id=123456).id,
)
def tearDown(self):
SocialNetwork.objects.all().delete()
Platform.objects.all().delete()
User.objects.all().delete()
@patch('users.views.requests')
def test_success_kakao_signup(self, mocked_requests):
client = Client()
class MockedResponse:
def json(self):
return {
'id': 11111111,
'connected_at' : '2022-07-07T04:35:56Z',
'properties' : {
'nickname' : 'signup',
'profile_image' : 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_640x640.jpg',
'thumbnail_image': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_110x110.jpg'},
'kakao_account': {
'profile_nickname_needs_agreement': False,
'profile_image_needs_agreement': False,
'profile': {
'nickname': 'signup',
'thumbnail_image_url': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_110x110.jpg',
'profile_image_url': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_640x640.jpg',
'is_default_image': False
},
'has_email': True,
'email_needs_agreement': False,
'is_email_valid': True,
'is_email_verified': True,
'email': 'kakao-signup@kakao.com'
}
}
mocked_requests.get = MagicMock(return_value = MockedResponse())
headers = {'HTTP_Authorization': 'mocked_access_token'}
response = client.get('/users/signin/kakao', **headers)
access_token = jwt.encode({'id': User.objects.latest('id').id}, settings.SECRET_KEY, settings.ALGORITHM)
self.assertEqual(response.status_code, 201)
self.assertEqual(
response.json(),{
'message' : 'ACCOUNT_CREATED',
'access_token' : access_token
}
)
@patch('users.views.requests')
def test_success_kakao_signin(self, mocked_requests):
client = Client()
class MockedResponse:
def json(self):
return {
'id': 987654,
'connected_at' : '2022-07-07T04:35:56Z',
'properties' : {
'nickname' : 'test',
'profile_image' : 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_640x640.jpg',
'thumbnail_image': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_110x110.jpg'},
'kakao_account': {
'profile_nickname_needs_agreement': False,
'profile_image_needs_agreement': False,
'profile': {
'nickname': 'test',
'thumbnail_image_url': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_110x110.jpg',
'profile_image_url': 'http://k.kakaocdn.net/dn/bxmEfD/btryJYaBk0R/oPpMxh2NK73LSYT98Xl1Vk/img_640x640.jpg',
'is_default_image': False
},
'has_email': True,
'email_needs_agreement': False,
'is_email_valid': True,
'is_email_verified': True,
'email': 'test@kakao.com'
}
}
mocked_requests.get = MagicMock(return_value = MockedResponse())
headers = {'HTTP_Authorization': 'mocked_access_token'}
response = client.get('/users/signin/kakao', **headers)
access_token = jwt.encode({'id': User.objects.latest('id').id}, settings.SECRET_KEY, settings.ALGORITHM)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(),{
'message' : 'SIGN_IN_SUCCESS',
'access_token' : access_token
}
)