
다양한 취업공고들을 보니까, test 에 대해서 언급한 기업들이 많더라구요
그래서 test에 대하여, 그 중 Unit test에 대해 자세히 알아보도록 할게요!
시작하겠습니다 :)
▶ Manual Test
* 사람이 직접 실행하는 테스트
* 누구나 직관적으로 큰 계획 없이 테스트 실행가능
* 실행속도 ↓ & 인력소모 ↑ & 불안정성 ↑ & 비용 ↑
★ 그래서 test 자동화가 중요!!
테스트가 반복적으로 자주 실행될 수 있도록!
빠지는 부분이 없이 실행 될 수 있도록!
▶ 시스템 테스트 방법 3가지

1. UI(User Interface) test / End-To-End test
* 사용자가 실제로 시스템을 사용하는 방식과 가장 동일하게 테스트
* 프론트엔드와 백엔드까지 모든 시스템을 실행시키고 연결해야 할 수 있는 테스트
* 자동화가 가장 까다롭다
* 꼭 필요하지만 적게 사용하는 것이 좋은 test로 전체 test 중 대략 10% 정도 사용
2. Intergration test

* API를 로컬에서 실행시킨 후 HTTP 요청을 API 서버에 전송하여 올바른 HTTP 응답이 리턴되는지 확인
* 백엔드 API 시스템만을 실행한 뒤 지금 당장 구현한 특정 기능에 대해서 확인하는 방법
* UI test에 비해 시간이 짧고 간단한 편
* unit test 비해 자동화에 걸리는 공수가 더 크고 실행 속도가 오래 걸림
* 전체 테스트의 20% 정도를 추천
3. Unit test

* 테스트를 할 수 있는 가장 작은 단위(unit)를 테스트하는 코드를 작성해서 테스트 하는 것
* 시스템을 테스트한다는 개념보다는 코드를 직접 테스트하는 개념, 즉 코드로 코드를 테스트
* 함수나 메소드를 호출한 뒤 결괏값을 확인하는 코드를 실행
* 실행하기 쉬우며 실행속도가 빠르다
* 함수 단위로 테스트를 하다 보니 전체적인 부분을 테스트하기에는 제한적
* 가장 비중을 높게 두면 좋은 test로 전체테스트의 70%로 구성
▶ UNIT TEST
1. 용어
* Testcase : unittest Framwork의 테스트 조직의 기본단위
* Fixture : 테스트를 진행할 때 필요한테스트용 데이터 혹은 설정.
* Assertion : unittest에서 테스트하는 부분이 제대로 됐는지 확인하는 부분

2. 설계 원칙



▶ UNIT TEST 작성해보기
1. 아래와 같이 로그인 views.py를 작성했다고 가정한다!
class SignupView(View):
def post(self, request):
try:
data = json.loads(request.body)
REGEX_EMAIL = re.compile("^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
REGEX_PASSWORD = re.compile(
"^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$"
)
password = data["password"]
if User.objects.filter(email=data["email"]).exists():
return JsonResponse({"MESSAGE": "ALREADY_EXISTED_EMAIL"}, status=400)
if not REGEX_EMAIL.match(data["email"]):
return JsonResponse({"MESSAGE": "EMAIL_ERROR"}, status=400)
if not REGEX_PASSWORD.match(data["password"]):
return JsonResponse({"MESSAGE": "PASSWORD_ERROR"}, status=400)
hashed_password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
decoded_password = hashed_password.decode("utf-8")
User.objects.create(
name=data["name"],
email=data["email"],
password=decoded_password,
)
return JsonResponse({"MESSAGE": "SUCCESS"}, status=201)
except KeyError:
return JsonResponse({"MESSAGE": "KEY_ERROR"}, status=400)
2. 그렇다면 이것에 해당하는 unit test 를 작성하면 아래와 같이 될 것이다!
V setUp은 데이터를 넣는 과정이고, tearDown은 넣은 데이터를 삭제하는 과정으로 맨 마지막에 실행된다!
→ 각 test 함수들은 독립적으로 실행 되어야 하기 때문에 데이터 삭제가 중요
V 성공 케이스와 실패 케이스를 전부 테스트 해야 하며, 실패 케이스 중 다양한 케이스를 모두 작성해야 한다!
★ test 파일의 이름은 test로 시작해야 하며, 함수 이름도 test로 시작해야 한다!


import json
from django.test import TestCase, Client
from .models import User
class SignUpTest(TestCase):
def setUp(self):
User.objects.create(
email="bbb@wecode.com",
name="파이썬",
password="abcde12345@",
)
def tearDown(self):
User.objects.all().delete()
def test_signup_success(self):
client = Client()
user = {
"email": "aaa@wecode.com",
"name": "깔끔한",
"password": "abcde12345@",
}
response = client.post(
"/users/signup", json.dumps(user), content_type="application/json"
)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.json(), {"MESSAGE": "SUCCESS"})
def test_duplication_user(self):
client = Client()
user = {
"email": "bbb@wecode.com",
"name": "탄탄한",
"password": "abcde12345@@",
}
response = client.post(
"/users/signup", json.dumps(user), content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {"MESSAGE": "ALREADY_EXISTED_EMAIL"})
def test_email_format_error(self):
client = Client()
user = {
"email": "cccwecode.com",
"name": "파이썬",
"password": "abcde12345@",
}
response = client.post(
"/users/signup", json.dumps(user), content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {"MESSAGE": "EMAIL_ERROR"})
def test_password_format_error(self):
client = Client()
user = {
"email": "ddd@wecode.com",
"name": "파이썬",
"password": "abcde12345",
}
response = client.post(
"/users/signup", json.dumps(user), content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {"MESSAGE": "PASSWORD_ERROR"})
def test_key_error(self):
client = Client()
user = {
"email": "eee@wecode.com",
"name": "파이썬",
}
response = client.post(
"/users/signup", json.dumps(user), content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {"MESSAGE": "KEY_ERROR"})
3. 마지막으로 아래의 명령어로 test파일을 실행시켜본다.
python manage.py test
그렇다면, 25개의 test 파일이 실행됐고, 모두 OK가 됐음을 알 수 있다!

▶ UNIT TEST의 중요성
위의 실제 views.py 와 tests.py를 확인해보면 알 수 있듯,
test 코드를 구현하는 것이 실제 코드를 구현하는 만큼, 혹은 그 이상의 공수가 든다.
그럼에도 불구하고 중요한 이유는,
대부분의 버그는 기본적인 unit test만 구현해도 잡을 수 있는 버그들이다.
버그가 발견되는 시점을 당길 수 있는 것이다.
▣ 참조
위코드 "unit test" 세션
책 "깔끔한 파이썬 탄탄한 백엔드"
'Django' 카테고리의 다른 글
[Django] 댓글, 대댓글, 페이지네이션 구현하기 (0) | 2021.11.06 |
---|---|
[Django] 구글로 이메일 보내기 (0) | 2021.10.21 |