Skip to content

Tag 13 WebClient & Integration Tests mit zufälligen IDs

AstridOttmann edited this page Mar 17, 2023 · 2 revisions

WebClient

Ziel: wir möchten auf eine externe API zugreifen, z. B. die Futurama-API, und uns Charaktere zurückgeben lassen.

Workflow:

Infos über die API einholen

  • googeln nach futurama REST-API
  • alle Infos zur Verwendung einer API, u. a. wie sich die URL zusammensetzt, Basis-URL, Endpunkte, Querys, Datenstruktur findet man immer in den Documentations, hier REST auswählen)

Backend schreiben, dass diese Daten abruft

  • beim Erstellen eines neuen Projekts mit Spring neben Spring Web auch Spring Reactive Web auswählen
  • wir benötigen:

a) Controller: Endpunkt, der die Anfrage

GET https://localhost:8080//api/futurama entgegennimmt, z. B. vom Postman, und sie an den Service weiterleitet

b) Service: ruft dann die externe API auf, stellt die Anfrage

GET https://api.sampleapis.com/futurama +entsprechende Pfad-Ergänzung. Die Daten die zurückkommen werden vom Service entgegengenommen, wieder an den Controller weitergegeben und von diesem an Postman.

c) Modelklassen: Klassen oder Records, mit denen wir die Datenstruktur unserer Response nachbauen

Screenshot 2023-03-17 at 3 01 26 AM

Code Controller:

  • GET-Mapping ruft Methode des Service auf

Screenshot 2023-03-17 at 3 18 54 AM

Code Service:

  • für den Zugriff auf die externe API benötigen wir den WebClient
  • WebClient = umfangreiches Framework mit dem komplexe Anfragen vorbereitet und durchgeführt werden können
  • in die Klammern nach create wird die Basis-URL eingesetzt

Screenshot 2023-03-17 at 3 34 38 AM

  • Dependency in die pom.xml einbinden:
Screenshot 2023-03-17 at 3 33 00 AM
  • wir schreiben eine Methode, die uns einen Charakter zurückgeben soll

Screenshot 2023-03-17 at 3 38 01 AM

  • hierzu nutzen wir den WebClient mit .get
  • die URL bekommt die notwendige Pfadergänzung (siehe Documentations)
  • mit .retrieve() und .toEntity() geben wir an, in welcher Form wir die Daten erhalten wollen
  • hier müssen wir eine Datenform in Java angeben, die dem entspricht, was wir von der API zurückbekommen
  • dafür entsprechende Klassen oder Records anlegen; sind die Daten verschachtelt, müssen wir das mit unseren Records nachbauen
  • Daten, die zurückkommen, genau anschauen: pro geschweifter Klammer eine Klasse/Record erstellen, eckige Klammert heißt, es ist eine Liste
  • Eigenschaften in Objekten, die wir nicht wollen, können einfach weggelassen werden

Screenshot 2023-03-17 at 3 53 59 AM

Screenshot 2023-03-17 at 3 54 33 AM

  • mit .block() sagen wir, dass wir auf das Ergebnis warten
  • im return holen wir uns mit .getBody() den Body, die Daten die wir möchten
  • .requireNonNull() benutzen wir, um Warnungen zu vermeiden
  • wenn die API eine Liste zurückgeben soll, geben wir bei .toEntity() folgendes ein:

Screenshot 2023-03-17 at 4 02 32 AM

  • jetzt können wir unseren Server starten und eine Request z. B. bei Postman eingeben
  • wir bekommen die gewünschten Daten und können mit diesen weiter arbeiten

Link: free API's

Integration Tests mit zufälligen IDs

In unserem Beispiel testen wir, ob bei einem Post-Request einer Bestellung eben diese Bestellung wie gewünscht zurückgegeben wird. Die Bestellung hat folgende Eigenschaften:

  • zufällige ID
  • Produktliste

Problem: zufällige ID lässt sich nicht vorhersagen, wie sollen wir also testen, ob die richtige ID zurückgegeben wird?

Eine Möglichkeit: wir lassen die Abfrage nach der ID weg. In unserem Beispiel prüfen wir also zunächst nur die Produktliste der Bestellung. Im Anschluss prüfen wir dann, ob eine Bestellungs-ID vorhanden ist, aber nicht, wie sie aussieht.

@Test
    void postOrder() throws Exception {
        String responseBody = mockMvc.perform(post("/api/orders")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("""
                                []
                                """))
                .andExpect(status().isOk())

  //*******Hier prüfen wir nur auf die Produktliste, nicht auf die ID!!********    
                .andExpect(content().json("""             
                        {
                            "products": []            
                        }
                        """))

       //*******Hier prüfen wir, ob eine ID vorhanden ist!********
                .andExpect(jsonPath("$.id").isNotEmpty())   

Um zu prüfen, ob die Bestellung auch tatsächlich im Order-Repository gespeichert wurde:

  1. erstellen wir zunächst eine String-Variable mit dem Namen responseBody, in die wir das Ergebnis unseres Post-Requests speichern.
  2. sorgen wir dafür, dass das Ergebnis des Post-Requests auch wirklich als String gespeichert wird.
  3. erstellen wir einen Object-Mapper.
  4. nutzen wir den Object-Mapper, um unseren String responseBody, der im JSON-Format vorliegt, in ein Java-Object vom Typ Order zu konvertieren.
  5. prüfen wir, ob die Order wirklich im Order-Repository gespeichert wurde
@SpringBootTest
@AutoConfigureMockMvc
public class OrderIntegrationTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    OrderRepository orderRepository;

//******** 3. erstelle ObjectMapper **********
    @Autowired
    ObjectMapper objectMapper;

    @Test
    @DirtiesContext
    void postOrder() throws Exception {

       
//******* 1. erstelle String-Variable  mit dem Namen responseBody und speichere dort den Post-Request ******
         String responseBody = mockMvc.perform(post("/api/orders")      
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("""
                                []
                                """))
                .andExpect(status().isOk())
                .andExpect(content().json("""
                        {
                            "products": []
                        }
                        """))
                .andExpect(jsonPath("$.id").isNotEmpty())

//****** 2. In den folgenden drei Zeilen sorgen wir dafür, dass der String responseBody auch wirklich ein String ist *********
                .andReturn()                                  
                .getResponse()                                 
                .getContentAsString();                        

 //******* 4. Konvertierung vom JSON Body in ein Java Objekt vom Typ Order ********
        Order order = objectMapper.readValue(responseBody, Order.class);

//******* 5. Prüfe ob die Order wirklich im Repository gespeichert wurde ********
        Order actual = orderRepository.get(order.id());
        Order expected = new Order(order.id(), List.of());

        assertEquals(expected, actual);
    }
}


Clone this wiki locally