inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! FastAPI 입문

테스트 코드 변경

TODO 테스트 코드 작성

해결된 질문

334

luke

작성한 질문수 4

0

저의 경우는 아래와 같이 해주어야 테스트 코드가 통과됩니다. 그 이후는 sql 도커의 데이터가 5개가 있어서 실제는 5개이기 때문이라 생각되어지는데요.

강의를 보면서 테스트코드 감을 못잡앗는데, 궁금한 점은 테스트 코드에서 user 변수에다가 id1 이고 test란 이름의 유저네임을 넣어주고 거기다가, todos를 목업으로 2개를 넣어줬는데, 왜 마지막에 assert할때는 user.todos에 넣어준 배열로 하는게 아닌 실제 db들어간 5개의 데이터로 assert로 체크하더라구요.

 

그러면 아래 mocker patch해준 부분이 제대로 안먹는건가요? 흠..

user = User(id=1, username="test", password="hashed")
user.todos = [
    ToDo(id=1, contents="FastAPI Section 0", is_done=True),
    ToDo(id=2, contents="FastAPI Section 1", is_done=False),
]

mocker.patch.object(UserRepository, "get_user_by_username", return_value=user)

 

def test_get_todos(client, mocker):
    access_token: str = UserService().create_jwt(username="test")
    headers = {"Authorization": f"Bearer {access_token}"}

    user = User(id=1, username="test", password="hashed")
    user.todos = [
        ToDo(id=1, contents="FastAPI Section 0", is_done=True),
        ToDo(id=2, contents="FastAPI Section 1", is_done=False),
    ]

    mocker.patch.object(UserRepository, "get_user_by_username", return_value=user)

    # order=ASC
    response = client.get("/todos", headers=headers)
    assert response.status_code == 200
    assert response.json() == {
        "todos": [
            {"id": 1, "contents": "FastAPI Section 0", "is_done": True},
            {"id": 2, "contents": "FastAPI Section 0", "is_done": True},
            {"id": 3, "contents": "string", "is_done": True},
            {"id": 4, "contents": "string", "is_done": True},
            {"id": 5, "contents": "string", "is_done": True},
        ]
    }

    # order=DESC
    response = client.get("/todos?order=DESC", headers=headers)
    assert response.status_code == 200
    assert response.json() == {
        "todos": [
            {"id": 5, "contents": "string", "is_done": True},
            {"id": 4, "contents": "string", "is_done": True},
            {"id": 3, "contents": "string", "is_done": True},
            {"id": 2, "contents": "FastAPI Section 0", "is_done": True},
            {"id": 1, "contents": "FastAPI Section 0", "is_done": True},
        ]
    }

python 리팩토링 orm FastAPI pytest

답변 1

0

신동현

안녕하세요. 말씀하신 것처럼 mocking이 제대로 동작하고 있지 않고 있을 가능성이 높은 것 같습니다. 보통 오타가 있는 경우에 mocking이 동작하지 않을 수 있는데요.

router 코드도 같이 첨부해주시면 더 자세하게 디버깅을 도와드릴 수 있을 것 같습니다.

0

luke

아래가 라우터 코드이며 깃허브에 있으신 코드와 동일합니다만 저는 왜 실제 db로 되고 목킹이 제대로 안되는지 모르겠네요 . 보통 테스트 코드는 위의 글처럼 2개로 했으면 2개만 검증하고 넘어가는게 맞는걸까요? 그렇게 되어야 할거라고 생각되네요 실제 db는 투두가 100개 천개가 될수도 잇는데 저렇게 하드코딩해서 테스트 검증하는건 이상할거라 생각되어서요.

@router.get("", status_code=200)
def get_todos_handler(
    access_token: str = Depends(get_access_token),
    user_service: UserService = Depends(),
    order: str | None = None,
    user_repo: UserRepository = Depends(),
    todo_repo: ToDoRepository = Depends(),
) -> ToDoListSchema:
    username: str = user_service.decode_jwt(access_token=access_token)
    user: User | None = user_repo.get_user_by_username(username=username)
    if not user:
        raise HTTPException(status_code=404, detail="User Not Found")

    todos: List[ToDo] = todo_repo.get_todos()

    if order and order == "DESC":
        return ToDoListSchema(
            todos=[ToDoSchema.model_validate(todo) for todo in todos[::-1]]
        )
    return ToDoListSchema(todos=[ToDoSchema.model_validate(todo) for todo in todos])

1

신동현

안녕하세요. 강의와 동일하게 동작하기 위해서는 router 코드에 todos: List[ToDo] = todo_repo.get_todos() 부분을 todos: List[ToDo] = user.todos 로 바꾸어주셔야 합니다.

eager-loading을 이용하여 user 테이블에서 todo 테이블을 JOIN하여 가져온 뒤, todos를 바로 사용하고 있습니다.

자세한 내용은 섹션 5: (실습) JWT 사용 강의를 참고 부탁드립니다 :D

이어서 질문주신 테스트에서 데이터베이스의 데이터를 검증하는 것과 mocking 하는 것의 차이는 테스트의 목적에 따라 결정하시면 됩니다.

현업에서는 테스트 코드에서 실제 production 환경의 데이터베이스에 테스트를 수행하는 경우는 없고, 보통 docker를 이용해서 테스트를 위한 데이터베이스를 구성하여 데이터를 저장하고 출력하는 테스트를 하는 경우가 있는데 이를 intergration test라고 부릅니다.

intergration test는 다양한 시스템 간의 통합을 검증하는 절차인데, 실제 데이터베이스에 I/O를 발생시키기 때문에 intergration test가 많아지면 전체적인 테스트 동작 시간이 오래 걸립니다.

이에 따라 intergration test가 굳이 필요하지 않는 경우에는 해당 과정을 mocking으로 대체하곤 합니다.

본 강의에서도 intergration test가 필요하지 않다고 판단하여 데이터베이스 I/O에 대한 부분은 모두 mocking으로 처리하였습니다.

FasAPI Swagger UI에서 단일조회 todo_id 를 사용했는데, 입력값에 1을 넣으니 오류가 뜹니다 ㅠ

0

87

2

DB 질문

0

81

2

Post API 강의 질문

0

55

2

post 작성 오류

0

107

3

uvicorn 종료 문제

0

436

2

왜 return타입이 ToDo라는 스트링인가요?

0

130

2

ORM 연관관계

0

109

2

Oracle DB 연결과 관련해 질문이 있습니다..

0

153

2

섹션 2, 3의 PATCH API의 차이점

0

132

1

ORM 테이블 생성

0

119

1

테스트 코드 오류

0

177

1

orm relationship 정의 중 해당 에러 발생 시 어떻게 고쳐야 하는걸까요

0

214

3

FastAPI 폴더 구조에 대해 질문이 있습니다.

0

412

2

질문 있습니다.

0

161

2

ORM 개념

0

133

1

mysql root 비밀번호 변경관련

0

296

2

[질문] patch API

0

151

3

디자인 패턴

0

128

1

main.py 리로드문제

0

235

2

인터프리터 오류

0

286

4

로그 저장에 대한 질문입니다.

0

100

1

Internal Server Error

0

240

2

PATCH API - 수정

0

199

2

파이참 임포트 문제

0

263

1