프로젝트에 크롤링 TestCode를 적용해본 후기
1. Flask에서 TestCode를 적용해보자.
pkselect프로젝트를 진행할 때, TestCode를 적용해야겠다고 생각했다.
WHY?
이전에 크롤링 외주를 진행할 때 홈페이지 태그 등이 변경되어 클라이언트가 코드를 수정해달라는 요청을 받은 적이 있다.
그래서 로그인부터 대학교 LMS 시스템에 크롤링을 통해 접속하는 해당 서비스의 단점을 보완하고자 배포 전 TestCode로 올바르게 작동하는지 확인하도록 하였다.
/make_fake_data.py
테스트에 필요한 가짜 데이터를 생성하는 모듈이다.
from faker import Faker
from faker.providers import internet
import string
# api에 테스트 해보기 위한 데이터 생성 부분입니다.
# 어떤 필요한 데이터들을 생성해서 test를 해볼 것인가?를 주된 관점으로 작성해보았습니다.
# 서버에 대한 API 요청을 테스트 해볼 것이기에, 이에 필요한 요소들을 정리해보겠습니다.
"""
클라이언트 => 서버에 대한 요청 자체에 대한 Test입니다.
서버 => LMS서버에 대한 요청이 아닙니다...?
1. 파라메타 (GET, POST, PUT, DELETE 4개)
2. uri 에서 url을 뺀 부분 ( path 부분 ) # 제 서버로 보내야 의미가 있다고 생각했습니다., path부분의 임의의 문자로 지정하지 않은 이유는 fake에서 제공하는 path를 이용하고 싶어서 입니다.
4. port 번호
3. 2번에서 추출한 값을 http://localhost:포트번호/path 로 지정하고, 이 uri들을 저장
5. 3번에서 저장한 값을 GET, POST, PUT, DELETE에 맞게 요청이 올바른지 에 대한 TDD 진행
ex) http://localhost:80/login 으로 POST요청이 200이면 이건 잘못됐습니다. 로 하고 나머지는 전부 400 Bad Request로 처리가 되는지 확인하는 코드입니다. header, parameter등의 요소는 처리하지 않았습니다.
클라이언트 -> 서버 form data 부분은 따로 빼서 문법체크만 할 것입니다.
"""
def get_fake():
fake = Faker("ko_KR")
fake.add_provider(internet)
return fake
def fake_request_data(fake_cnt):
fake = get_fake()
temp_uri = fake.uri()
path = ""
true_path = "/login"
true_method = "POST"
true_status = 400
special_chr = "[-=+,#/\?:^$.@*\"※~&%ㆍ!‘|\(\)\[\]\<\>`']"
for i in range(len(temp_uri) - 1, -1, -1):
try:
path += temp_uri[i] if temp_uri[i] != "/" else 1
except:
path = path[::-1]
break
request_data_result = [
{
"uri": "http://localhost:" + str(80) + true_path,
"method": true_method,
"status_code": true_status,
"form_data_result": {
"pk_user_id": fake.numerify(text="#########"), # 9글자 숫자
"pk_user_pw": fake.numerify(text="#")
+ fake.lexify(
text="????"
+ "?"
* (fake.random_int(min=5, max=11) * fake.random_int(min=0, max=1)),
letters=(string.ascii_letters + string.digits + special_chr),
)
+ fake.lexify(text="?", letters=special_chr),
}, # id는 9글자, 비밀번호는 6자리 숫자(asd) 숫자 특수문자 포함 10자리 이상혹은 최대 16자리 , 첫 데이터는 통과하는 데이터 넣을거라, 항상 숫자 1 특수문자 1 을 포함하도록 하였음.
"status_code": "200",
}
for _ in range(fake_cnt)
]
return request_data_result
print(fake_request_data(1))
print(len(fake_request_data(1)))
# form_data_result는 서버 -> lms에도 이용하니까 따로 빼둬야하지 않을까 ? 아니면 요청 하나하나에 힘을 실어야하기에 ㅇㅇ
Faker모듈과 internet 모듈을 통해 가짜 클라이언트가 잘 생성된 것을 확인할 수 있다.
/test_api.py
api를 테스트하는 모듈이다.
"""
test_login_checker Test Case
"""
import sys, os
import json
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) #app을 import 하기 위함
from app import create_app
from config import config_dict
import unittest
from make_fake_data import fake_request_data
class MyTest(unittest.TestCase):
def setUp(self):
self.app = create_app(config_dict['testing'])
self.client = self.app.test_client()
def test_login_fail(self):
print("\n>>>>가짜 데이터를 생성하고, login_api를 검증해봅니다<<<< \n")
print(">>>생성할 가짜 데이터의 갯수를 입력해주세요 : ")
cnt = int(input())
print("\n")
fake_data = fake_request_data(cnt)
for index in range(cnt):
resp = self.client.post(
fake_data[index]['path'],
data = json.dumps(dict(
fake_data[index]['form_data_result']
)),
content_type = 'application/json',
follow_redirects = True)
format_resp = json.loads(resp.data.decode('utf-8'))
print("테스트 데이터 : ", fake_data[index]['form_data_result'])
print("응답 데이터 : ", format_resp)
self.assertEqual(format_resp['status'], fake_data[index]['status_code'])
print(">>>검증 완료<<< \n")
테스트 완료된 화면이다. 생성한 가짜 데이터로 내 api에 post요청을 보내본다.
2. 아쉬웠던 점
TestCode를 콘솔을 통해 커스터마이징하려하니, 잘 되지 않아서 작성하는데 시간이 꽤나 걸렸고 WAP(동아리) 프로젝트 제출 시간을 맞추고자 로그인 크롤러 API에만 테스트를 해본 것이 아쉽다. Config를 Console을 통해 주입하다보니 TEST코드도 콘솔을 통해 넣어야겠다라는 생각을 했었기 때문이다.
지금 다시 생각해보니 '올바른 ID 혹은 PW가 아닙니다.'를 뱉어내는 데이터는 무수히 많은데, 이를 다 검증할 수는 없지 않을까?라는 생각으로 검색을 해보니 TDD(테스트주도개발)이라는 방법론이 따로 있었다... 그럼에도 TestCode를 적용했을 때의 장점과 단점을 적어보자면
- TestCode의 장점
작성한 코드에 대해 TestCode가 없을 때 보다 있을 때 신뢰도가 더욱 보장된다. 랜덤으로 생성된 데이터가 내 함수를 체크해주니 신뢰도가 올라간 느낌이 들었다.
- TestCode의 단점
생산성이 저하된다. 간단하게 만들면 끝날 실제 코드가 큰 이유 없이 TestCode를 작성하게 된다면 생산성이 저하될 것이라고 느꼈다.
Flask에서 직접 가짜 데이터를 만들고 내가 만든 모듈을 테스트해보았는데, 이를 통해 TDD와 마이크로 프레임워크와는 잘 맞지 않다는 것을 알게 되었다. 사실 Flask가 간단한 API나 기능을 빠르게 만들기 위해 있는 것이라 대규모 프로젝트와 어울리지 않아서 그런 것이 아닐까? 대규모 프로젝트일수록 TDD의 두각이 나타날 것 같다. 기회가 된다면 적용 꼭 해보고 싶다!