- TIL. 최종프로젝트(6) 순차열이 어긋나는 경우 목차
주말에 테스트 코드를 작성하며 배운 점이다.
[주말 배운점]
DRF
<순차열이 어긋나는 경우>
주말에 테스트 코드를 쭉 작성했다.
그런데 마지막에 작성한 테스트에서 예기치 못한 에러가 났고 해결하는데 꽤 애를 먹었다.
이번에 배운점이 있다면 예기치 못한 에러는,
특이한 곳 (새로운 작성법을 쓴곳)에서 난다는 것이다.
퀴즈 불러오기 테스트를 작성했는데 정상적으로 테스트가 실행됬다.
퀴즈 신고하기 테스트를 작성했더니, 신고하기는 잘 되는데 불러오기가 문제가 생겼다.
서로 제외해가며 테스트해보니, 확실히 신고하기 테스트가 불러오기 테스트에 문제 원인이었다.
인터넷으로 찾아보니, 테스트 순서에 따라 예기치 못한 에러가 날수 있다고 했다.
※ 테스트 순서는 따로 명시하지 않는다면 테스트명 알파벳순서라고 한다.
순서를 바꿔주니 둘다 에러가 안났다.
다시 순서를 돌려놓고, 왜 에러가 일어나는지 분석해봤다.
- 퀴즈 불러오기 기능은 DB의 퀴즈개수가 10개보다 적다면 장고에러를 발생한다.
- 지금 에러나는 내용은 장고에러가 아니다. 퀴즈 쿼리셋은 작성하는데 요소 갯수가 0개다.
- 즉 퀴즈를 10개 만드는 동작은 동작했으나 쿼리셋으로 한개도 못찾고 0개를 반환하고있다.
내가 만든 테스트는 기능에 대해 결과 스테이터스, 결과 값, DB변동까지 검사한다.
결과 값의 길이까지 검사하게 했더니, 이런 문제점을 찾아낸 것이었다.
(퀴즈 불러오기는 퀴즈를 10개 불러와야 한다.)
계속 한단계씩 분석해보다가, 퀴즈 제너레이터에서 쿼리를 어떻게 만드는 지 검사해봤다.
역시나 빈 쿼리셋을 만든다.
그럼 그 전단계 quiz.objects 호출을 검사해봤다.
문제점을 발견했다.
테스트 셋업은 테스트 실행시마다 데이터를 만들고 지운다.
퀴즈 신고하기 테스트 단위가 먼저 실행되며 퀴즈를 10개 만들고 없앤다.
다음 퀴즈 불러오기를 테스트 하며 새 퀴즈를 10개 만들고 없앤다.
(둘은 클래스로 구분되어 있다. 두 테스트에 부모클래스에서 setup이 이뤄진다.)
그런데 이 오브젝트들을 보니, 오브젝트 1~10, 오브젝트 11~20으로 만들고 없앤다.
그래서 퀴즈 제너레이터가 문제를 일으켰던 것이다.
이번에 새로 작성한 기능인데다가 이런 예외에 대해 예상도 못했고,
검출 동작도 없으니 알기 어려웠던 것이다.
확장해서 생각해보자면, 퀴즈 DB에 ID의 순차열은 언제든 어긋날 여지가 있다.
DB 데이터의 출납이 있다면 더욱 그렇다.
데이터가 중간에 하나라도 비면 안되니 적절하지 않다.
기존 작성했던 퀴즈 제너레이터는 오브젝트 수를 이용해서,
1~오브젝트 수의 순차열을 만든다음 랜덤한 10개의 퀴즈의 id를 골라냈다.
class QuizGenerator:
def generate():
quiz_count = Quiz.objects.count()
generate_count = 10
quiz_ids = random.sample(range(1, quiz_count), k=generate_count)
return Quiz.objects.filter(id__in=quiz_ids)
기존 제너레이터의 코드이다.
이걸 주말에 핫픽스를 한번 했고, 오늘 한번더 보강했다.
class QuizGenerator:
def generate():
quiz_objects_ids = Quiz.objects.values_list("id", flat=True)
id_list = list(quiz_objects_ids)
generate_count = 10
quiz_ids = random.sample(id_list, k=generate_count)
return Quiz.objects.filter(id__in=quiz_ids)
이렇게 수정했다.
오브젝트를 참고하되 id값만 불러오고 그 id리스트에서 직접 10개를 골라내도록 했다.
이렇게 작성할 것이라면 그냥 전체 오브젝트 조회후
order by ?로 무작위 10개를 정렬하고 슬라이싱 하는 방법이랑 비슷해진다.
게다가 위의 경우는 오브젝트 조회가 두번있다.
현재로써는 작성한 방법의 동작이 빠르길 바란다.
나중에 많은 데이터를 기반으로 어떤게 빠른지 비교해봐야겠다.