Jak napisać poprawnie test do endpointa z listą miast

1

(UPROSZECZNE) Mam prosty endpoint z listą miast w Django. Jest to wymagane przez biznes bo sprzedajemy na zewnątrz (przez API) listę miast z danego województwa codziennie aktualizowaną itd. Mamy 200 klientów, którzy płacą nam ponad 40000 zł za to jedno API (korzystają bez limitu).

Załóżmy, że klasa, która zwraca miasta robi trochę więcej ale dla uproszenia przyjmujemy, że wystawia jedną metodę publiczną.

class Cities:
    def get_cities(self):
        """Do something non trivial"""
        return ["Kraków", "Warszawa", "Poznań"]


def get_cities(request):
    return Cities().get_cities()


urlpatterns = [
    ("/cities", get_cities, name="cities"),
]

@Riddle: Jak tu napisać poprawny test? Bo ja bym napisał po prostu:


class Test:
    def test_get_cities(self)
        # Prepare data to make response contain three cities
        city_1 = "Kraków"
        city_2 = "Warszawa"
        city_3 = "Poznań"
        
        response = self.client("cities")

        self.assertEqual([city_1, city_2, city_3], response.json())
        

Ale wydaje mi się, że byłoby to błędne bo testowałbym implementację i teraz nie wiem jak to zrobić. Tak samo parsowałbym output (?) więc to też byłoby nie poprawne.

Proszę nie skupiać się na to, że klasa Cities mogłaby być metodą itd. bo jest to uproszony przykład i normalnie ta klasa przyjmowała by parametry.

1

Z tego co widzę, to na razie rozumiem że ten endpoint ma zwracać constant JSON'a z listą miast, więc zrobiłbym coś podobnego do Ciebie.

Test samego endpointa, bo logiki tutaj nie ma żadnej.

def get_cities(request):
    return ["Kraków", "Warszawa", "Poznań"]

urlpatterns = [
    ("/cities", get_cities, name="cities"),
]
def test_get_constant_cities(client)
  # when
  response = client.get("/cities")
  # then
  assert response.json() == ["Kraków", "Warszawa", "Poznań"]      

Jeśli jednak wymagania się zmienią, dojdzie więcej logiki, to bardzo prawdopodobne że testy się zmienią.

Wszystko się sprowadza do tego co ten endpoint ma robić, czego nie powiedziałeś. Skupiłeś się tylko na implementacji, że Twój handler zwraca list[str], i dlatego cieżko cokolwiek podpowiedzieć.

0

No a co innego ma robić. Zawsze endpointy muszą zwracać dane w jakimś formacie. Jak wyobrażasz sobie endpoint bez formatu danych?

0

@anonimowy: A ten format jest ważniejszy niż dane? Co czy zmiana kolejności obiektów będzie błędem, czy nie?

0

Kolejność nieistotna ale musi być zawsze taka sama. Format jest nie istotny, ale endpoint zawsze ma jakiś format, który jest podany w dokumentacji dla klientów więc oni na nim bazują tworząc swoje aplikacje korzystające z niego

1

@anonimowy: Kolejność nieistotna a musi być taka sama żeby system zawsze zwracał to samo dla tych samych wejść

A może sprawdzasz nie to co trzeba? Jeżeli masz zhardkodowaną stałą, to faktycznie możesz się spodziewać, że string zawsze będzie tym samym stringiem, ale co jeżeli w którymś momencie wskoczy tam baza danych i wynik będzie zwracany z select * from miasta? SQL, jeżeli nie wskażesz mu jawnie porządku przez order by ma prawo zwrócić ci rekordy w dowolnej kolejności. Dodasz do zapytania dodatkową klauzulę, żeby "zawsze mieć to samo", chociaż jest to wymagane jedynie przez testy?
Jeżeli klient płaci ci za api, które zwraca miasta, to testuj dokładnie to. Mają być miasta, a nie wsie, ma być ich dokładnie ileś tam, mają się nie powtarzać i ma tam być Warszawa, Otwock i Pacanów. Jeżeli klient płaci ci za dostarczenie zbioru (Set), to nie ma sensu testowanie, czy kolejność jest właściwa, bo zbiór nie ma kolejności.
Wniosek - jeżeli testujesz więcej niż chce od ciebie kontrakt z klientem, to testujesz implementację, a nie funkcjonalność.

0

No kurde mam API, które zwraca listę. Kolejność ma być zawsze taka sama więc pewnie wrzucę sobie jakiegoś order by. Mimo, że w dokumentacji nie ma nic o sortowaniu to sortuję to żeby zawsze zwracać to samo (co już jest implementacją, bo mógłbym sortować w inny sposób)

1 użytkowników online, w tym zalogowanych: 0, gości: 1