DaftAcademy / daftacademy-python_levelup-spring2020

20 stars 10 forks source link

Testowanie asynchroniczne #40

Closed Kaketo closed 4 years ago

Kaketo commented 4 years ago

Mam problem z lokalnym testowaniem mojej aplikacji. W Swaggerze endpoint /tracks/composers działa bez problemu i zwraca status 200 oraz zawartość, a pytest nie chce mi przepuscić poniższego testu. Czym może to być spowodowane?

Kod aplikacji:

import aiosqlite
from fastapi import FastAPI, Response, status
from pydantic import BaseModel

app = FastAPI()

@app.on_event("startup")
async def startup():
    app.db_connection = await aiosqlite.connect('chinook.db')

@app.on_event("shutdown")
async def shutdown():
    await app.db_connection.close()

@app.get("/tracks/composers")
async def get_tracks_by_composer(composer_name: str):
    app.db_connection.row_factory = lambda cursor, x: x[0]
    cursor = await app.db_connection.execute("SELECT Name FROM tracks WHERE Composer = :composer_name ORDER BY Name",
        {'composer_name': composer_name})
    tracks = await cursor.fetchall()

Kod testów:

from fastapi.testclient import TestClient
import pytest
from main import app

def test_get_tracks_by_composer():
    with TestClient(app) as client:
        response = client.get("/tracks/composers", json = {"composer_name": "Toby Smith"})
        assert response.status_code == 200

Testy wywalają się za każdym razem, bo mój response ma kod 422, przykład:

______________________________________ test_get_tracks_by_composer ______________________________________

    def test_get_tracks_by_composer():
        with TestClient(app) as client:
            response = client.get("/tracks/composers", json = {"composer_name": "Toby Smith"})
>           assert response.status_code == 200
E           assert 422 == 200
E            +  where 422 = <Response [422]>.status_code

test_main.py:16: AssertionError
DziurewiczPiotr commented 4 years ago

Hej! Błąd masz w kodzie testu. Twój endpoint nie przyjmuje obiektu json, tylko parametr composer_name

Kaketo commented 4 years ago

@DziurewiczPiotr To w takim razie w jaki sposób mogę przekazać ten parametr w teście? Bo przekazanie samego nazywanego argumentu nie działa:

def test_get_tracks_by_composer():
    with TestClient(app) as client:
        response = client.get("/tracks/composers", composer_name = "Toby Smith")
        assert response.status_code == 200

Wracając jeszcze do jsona, w poniższym przypadku test normalnie działa i przyjmuje jsona jako argument. Czy mam rozumieć, że jak mamy więcej niż jeden argument to automatycznie jest wymagany json?

Np. w endpoincie:

@app.get("/tracks")
async def get_tracks(page: int = 0, per_page: int = 10):

i teście:

def test_get_tracks():
    with TestClient(app) as client:
        response = client.get("/tracks", json = {'page': 2, 'per_page': 1})
DziurewiczPiotr commented 4 years ago

@Kaketo Tutaj odsyłam do dokumentacj requests na których bazuje TestClient: https://requests.readthedocs.io/en/master/user/quickstart/#passing-parameters-in-urls

W drugim przypadku test działa jedynie dlatego ze parametry page oraz per_page mają wartości domyślne. Tutaj odsyłam do dokumentacji fastapi i tesowania z pomocą TestClient: https://fastapi.tiangolo.com/tutorial/testing/#extended-testing-file

zernij sobie na test ::test_create_item i funkcję create_item()

Kaketo commented 4 years ago

Wszystko jasne, @DziurewiczPiotr bardzo dziękuję za pomoc! :+1: