create account

[Python #15] [Django #8] 구현된 기능, 테스트 해보자! by june0620

View this thread on: hive.blogpeakd.comecency.com
· @june0620 ·
$1.34
[Python #15] [Django #8] 구현된 기능, 테스트 해보자!
pixabay
https://cdn.pixabay.com/photo/2019/05/14/17/07/web-development-4202909_1280.png

간단한 기능이면 대충 테스트해 보고 넘어가겠지만 경우의 수가 많은 케이스는 테스트를 거치고 다음으로 넘어가야 할 것 같다. QA가 자기가 만든 기능을 테스트 안 하는 것도 무책임한 거 같고... 

다행히 python에서 unittest라는 라이브러리를 제공하고, django도 이를 기반으로 test 관련 라이브러리를 제공한다. app 디렉토리에 친절하게 `tests.py` 파일도 자동으로 생성해 주는 클라스. (물론 빈 파일).
여기에 테스트 코드를 넣어보자. 

##### 케이스 조합 
가장 손이 많이 가는 건 테스트 케이스 조합이다. 
tags, titles, texts 세 가지가 모두 list이고, 입력 텍스트 제한이 별로 없다.  태그에 영어 소문자만 입력 가능한 것만 제외하면 말이다. 
대충 봐도 테스트 케이스 조합이 50개는 나올 것 같다. 검색 기능 하나에 50개 케이스는 좀 아닌 것 같아 아래와 같이 최소한의 값으로 추려본다.

|Name|value1|value2|value3|value4
|---|---|---|---|---
|TAGS|결과 없는 값 | 빈 리스트 | list 크기 1인 정상값 | 빈 스트링
|TITLES|결과 없는 값 | 빈 리스트 | list 크기 2인 정상값 | 특수문자와 숫자
|TEXTS|결과 없는 값 | 빈 리스트 | list 크기 3인 정상값 | 빈 스트링

PICT의 IF 문으로 좀 더 필터링하면 적당한 조합이 나올 것 같다.  <sub>예전 글 [[IT] Pairwise 테스트는 MS PICT 로 조합하자~](https://steemit.com/hive-101145/@june0620/it-pairwise-ms-pict)</sub> 👇
```
TAGS: no_results,,valid_1,empty
TITLES: no_results,,valid_2,special and num
TEXTS: no_results,,valid_3,empty

if [tags] = "no_results" then [titles] = "no_results" and [texts] = "no_results" else [titles] <> "no_results" and [texts] <> "no_results";
if [tags] = "empty" then [texts] <> "empty";
if [texts] = "empty" then [tags] <> "empty";
```

최적의 케이스가 12개 케이스가 추출된다. (정말 최적인지는 알 길이 없다 ㅎㅎ)👇

![](https://cdn.steemitimages.com/DQmNf9cFB49Gv5VzNYPt1tKNXaRdRDWWfkhbG5JkZds6sSE/image.png) 

##### 코드 작성
unittest의 기본 사용법만 익히고 넘어가자. 
1. 우선 `tests.py`에 SearchTest 클래스를 만들고 TestCase를 상속받는다. 
2. 테스트 케이스 함수명은 test로 시작한다. 이를 기준으로 unittest가 실행된다고 한다. 
```
from django.test import TestCase
from .services import Search


class SearchTest(TestCase):

    def test_01_empty_tag(self):
        query = {
            'tags': [''],
            'titles': ['#2'],
            'texts': ['사랑', 'Pairwise', '区块链']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_02_valid_title(self):
        query = {
            'tags': [],
            'titles': ['#2'],
            'texts': ['']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_03_valid_all(self):
        query = {
            'tags': ['kr'],
            'titles': ['#2', '검색'],
            'texts': ['사랑', 'pairwise', '블록체인']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_04_valid_body(self):
        query = {
            'tags': [],
            'titles': [],
            'texts': ['pixabay', '区块链', 'Pairwise']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_05_valid_tag_and_title(self):
        query = {
            'tags': ['cn'],
            'titles': ['#2'],
            'texts': []
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_06_valid_all(self):
        query = {
            'tags': [''],
            'titles': [],
            'texts': []
        }
        s = Search(query)
        self.assertTrue(s.search_posts())

    def test_07_valid_title(self):
        query = {
            'tags': [],
            'titles': ['selenium', 'java #2'],
            'texts': []
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_08_no_results(self):
        query = {
            'tags': ['nononononono'],
            'titles': ['ttttt'],
            'texts': ['aaaaaa']
        }
        s = Search(query)
        self.assertFalse(s.search_posts())

    def test_09_valid_tags_and_titles(self):
        query = {
            'tags': ['kr'],
            'titles': ['#2', '검색'],
            'texts': ['']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_10_valid_tags_and_titles(self):
        query = {
            'tags': [''],
            'titles': ['#2', '검색'],
            'texts': []
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_11_valid_tags(self):
        query = {
            'tags': ['kr'],
            'titles': [],
            'texts': ['']
        }
        s = Search(query)
        self.assert_text_contains(query, s.search_posts())

    def test_12_empty_list_all(self):
        query = {
            'tags': [],
            'titles': [],
            'texts': []
        }
        s = Search(query)
        self.assertTrue(s.search_posts())

    def assert_text_contains(self, query: dict, blogs: list):
        self.assertTrue(blogs)
        all_q = query['tags'] + query['titles'] + query['texts']
        for blog in blogs:
            comm = blog['comment']
            cont = comm['json_metadata'] + comm['body'] + comm['title']
            any_one = any(query.lower() in cont.lower() for query in all_q)
            self.assertTrue(any_one)



```

##### 테스트 실행
`python workspace/my_app/manage.py test my_app`으로 실행하면 테스트가 실행된다. 처음엔 이슈가 많이 나와 현타가 좀 왔지만.... 다행히 지금은 전부 OK가 떨어진다. 
![](https://cdn.steemitimages.com/DQmUcrMY4iNzDeT13w33tre3kad6yNGrkBejcEJRahBGDdv/image.png)

기능 수정이 있을 때마다 실행하는 용도로 사용하면 딱 좋을 것 같다. 
좀 더 지켜보면서 케이스를 더 추가해야겠다. (또한 data-driven 테스트도 연구해 봐야겠다)

***

**[Cookie 😅]**
Python 3.7.4
Django 2.2.4
steem-python 1.0.1
goorm IDE 1.3

참고한 글: 
https://docs.python.org/ko/3/library/unittest.html
https://docs.djangoproject.com/ko/3.1/topics/testing/
https://docs.djangoproject.com/ko/3.1/intro/tutorial05/
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authorjune0620
permlinkpython-15-django-8-qg15bp
categoryhive-132971
json_metadata{"app":"peakd/2020.08.3","format":"markdown","tags":["kr","mini","whalepower","palnet","dblog","dev","django","python"],"users":["june0620"],"links":["https://steemit.com/hive-101145/@june0620/it-pairwise-ms-pict","https://docs.python.org/ko/3/library/unittest.html","https://docs.djangoproject.com/ko/3.1/topics/testing/","https://docs.djangoproject.com/ko/3.1/intro/tutorial05/"],"image":["https://cdn.pixabay.com/photo/2019/05/14/17/07/web-development-4202909_1280.png","https://cdn.steemitimages.com/DQmNf9cFB49Gv5VzNYPt1tKNXaRdRDWWfkhbG5JkZds6sSE/image.png","https://cdn.steemitimages.com/DQmUcrMY4iNzDeT13w33tre3kad6yNGrkBejcEJRahBGDdv/image.png"]}
created2020-09-02 11:59:51
last_update2020-09-02 11:59:51
depth0
children0
last_payout2020-09-09 11:59:51
cashout_time1969-12-31 23:59:59
total_payout_value0.701 HBD
curator_payout_value0.640 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length5,497
author_reputation118,592,211,436,406
root_title"[Python #15] [Django #8] 구현된 기능, 테스트 해보자!"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id99,408,777
net_rshares5,853,206,390,614
author_curate_reward""
vote details (53)