Unit test : 단위별로 확인하기

채록·2021년 3월 13일
0

Python & Django

목록 보기
28/34
post-thumbnail

0. Testing Pyramid

시스템(로직, 코드)가 제대로 동작하는지 확인하는 방법에는 3가지로 나눌 수 있다.

  • E2E test
  • Integration test
  • Unit test

이중에서 내가(BE) 이제껏 사용하던 방법은 Integration test이다.



1. E2E(UI) test

Endpoint test : 종단(Endpoint) 간 테스트로 사용자의 입장에서 테스트 하는 것.
만들어 놓은 화면에서 직접 값을 입력하여 제대로 출력이 되는지 확인하는 것으로 사용자의 동작을 모사해야 하기 때문에 사용자 입장의 Workflow와 Laytency를 측정하고 점검할 수 있다.

위 세가지 테스트 방법들 중에서 가장 까다롭고(작성 난이도를 얘기하는 것 아님) 비용이 많이 든다.


2. Integration test

위에서 예시로 들었던 httpie 혹은 postman을 사용해 테스트 할 수 있다.
모듈을 통합(Integrate)하는 단계에서 수행하는 테스트로

# 예시 (posting 경로로 불러올 수 있는 data 보기)
> http -v POST 0:8000/posting title='게시물제목', image_url='http://jpg', content='게시물내용'

위와 같은 httpie를 통한 테스트를 예로 들면 runserver로 server를 실행하면서 viewmodel 클래스를 병합(integration)하여 테스트 하게 된다.

🙌 단위 테스트가 끝난 모듈을 통합하는 과정에서 발생할 수 있는 오류를 찾는 테스트가 통합 테스트(integration test)인데 이제껏 unittest의 개념을 몰랐기 때문에 바로 integration test를 수행했던 것이다.


3. Unit test

unit 단위로 테스트 하는 것! 프로그램을 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지 검사하고 이를 통해 문제 발생 시 정확하게 어느 부분이 잘못되었는지를 재빨리 확인할 수 있게 해준다.
함수와 class 단위로 테스트가 가능하다!




E2E test는 BE인 나혼자 하는것이 불가능 하기 때문에 포스팅은 못한다!

I. 작성 : Unit test

위에서 말했듯 함수와 클래스별로 테스트하는것이다. 또한 success 상황 뿐만이 아니라 어떤 상황에서 어떤 오류가 날 것인지에 대한 테스트도 같이 수행해주어야 한다.


1. Unittest - Flow

  • setUp : test용 instance를 만들고
  • test_@@ : test 하고
  • tearDown : test용 instance를 삭제한다

어떤 것을 위쪽에 작성해주는지는 flow에 영향을 끼치지 않는다. 나의 경우 python 에 내장되어 있는 unittest 기능을 사용하는데 이 기능 자체에 setUp -> test -> tearDown순으로 flow가 흘러가게 되어있다.

setUp ??
unittest에서 사용할 instance들은 내 local db (혹은 내 실제 project와 연관된 db)의 instance를 가지고 테스트하지 않는다. 테스트 전용 instance들을 생성해 그것들이 view에 작성된 로직대로 구현되었을 시의 결과를 확인한다.


여기서 이렇게 생성되는 test용 요소들을 default db라고 부른다.

내가 test할 view의 로직은 다음과 같다.


2. GET : unit test

1) setUp

test에 필요한 instance들을 만들어 준다. 그러기 위해선 먼저 import 해주기!

Client() ??
unittest를 수행할대는 server가 실행되지 않아도 된다. 이는 Client() 덕분인데 변수 client에 지정해 server 가 실행되지 않고 있는 상황에서도 request를 만들어 view를 실행시킬 수 있다.


test할 ResumeView는 로그인 한 유저가 작성한 Resume list에 대한 데이터를 보내주는 로직이다. 때문에 setUp에서 유저가 만들 resume들을 작성해 준다.

id 2번인 resumefile은 현재 포스팅에서 불필요한 내용이므로 잠시 삭제했다. 원랜 있다...


2) tearDown

test가 끝난 후 default DB에 생성된 것들을 제거해 준다.


3) test_resume_get_success

test_@@ ??
test가 수행되는 메소드의 이름은 반드시 test로 시작해야 한다. 그래야 django가 인식할 수 있기 때문!

  • 해당 logic은 @login_decorator가 달려있는 로직이다. 때문에 token이 있어야만 수행 가능하므로 tests.py에서 token을 생성해 전달해 주어야 한다.
  • client.get으로 실제 FE에서 BE로 GET 요청을 보내는 것을 수행해 준다. 이를 response에 담는다. 이때 요청에는 요청이 전달될 url 경로, 요청보내는 content의 타입(요청의 body에 내용이 없으므로 필요가 없을수도 있지만 일괄적으로 다 작성해 주었다.). 또한 토큰이 담길 headers를 함께 보내주어야 한다.
  • assertEqual : setUp으로 만든 default db의 instance들이 내 views.py 로직을 통해 출력되는 형태와, 실제로 나와야 하는 data의 형태 두개사이를 비교해 준다.

assert ??
위에서 사용한 Equel외에도 다양한 비교방법이 있다.

  • True : 두개의 값을 비교했을때 결과가 True면 ok
  • False : 두개의 값을 비교했을 때 결과가 False 면 ok


    더 많은 내용은 document에 있다.

4) test_resume_get_failed_invalid_token


해당 get 로직자체로는 큰 에러상황이 발생할만한게 없다. 굳이 고르자면 @login _decoraotr 로직에서 걸릴만한 것들? 그 첫번째로 유효하지 않은 token으로 내 로직에 접근했을 경우이다.


5) test_resume_get_failed_does_not_exist


token의 형태는 정상적이지만 login_decorator 로직을 통해 token이 복호화 되면서 나온 유저에 대한 정보가 존재하지 않을 경우 발생하는 에러이다. (user의 id는 2번까지밖에 없는데 token에 담긴 id가 3번일 경우)



2. POST : unit test

내 로직상 POST이지만 특별히 body에 담기는 내용이 없다.

  • user는 token으로 부터 그 정보를 제공받는다.
  • resume의 title은 user의 이름+기존에 작성된 resume갯수+1을 해서 자동으로 title이 지어진다.
  • introdue는 null=True이므로 입력하지 않는다.
  • POST 결과 JsonResponse로 새로 생성된 resume의 id 값을 보내준다.

  • 위에서 setUp으로 id 4번까지 만들었으므로 POST 결과 새로 생성될 resume의 id는 5번일 것이다.



II. 확인 : python manage.py test

unittest를 실행하기 위한 명령어 이다.
@@ 자리에 특정 app이름을 입력하면 해당 app 내의 tests.py만 실행된다.


위의 포스팅 내용 말고도 다른 test들이 있어서 13개다 ㅎ 어쨋든 모두 ok!!




III. Tip!

1. json.dumps()

위에서 작성한 예시들은 Mock사용도 필요없는 정말 간단한 unittest이다. post시에 body에 담겨야 할 내용들이 있어야 한다면 그 부분도 작성해서(예로 text라는 변수에 담는다고 가정) json.dumps(text)로 보내주어야 한다.


2. default DB의 PK

하나의 test class에서는 하나의 setUp 메소드만 있으면 된다.

setUp => test => tearDown

이렇게 진행된다. 하나의 test를 진행하는데 항상 위의 flow가 진행된다.
이때 setUp에서 만들어지는 Instance들이 하나의 test후 tearDown 으로 삭제가 되고, 그 다음 test에서 같은 내용이 생성된다고 할때 id가 늘어난다.

실제 db 에서도 id=1 인 Instance를 삭제하고 다른 하나를 만든다고 해서 id=1로 만들어지지 않고 id=2로 만들어지는것과 같은 맥락!!!

때문에 test에서 "setUp에서 다시 만들어지면 id=1이니가 그걸로 검사하면 되겠지?" 라고 하면 Fail이 뜨는거다.

이에 대한내용은 길어질것 같으니... 따로 포스팅 !!



  • setUp 한번에 하기! => 추가예정
  • tearDown 한번에 하기! => 추가예정
  • setUp시 생성 시간 지정하기! => 추가예정
profile
🍎 🍊 🍋 🍏 🍇

0개의 댓글