-
Notifications
You must be signed in to change notification settings - Fork 2
Tag 13 WebClient & Integration Tests mit zufälligen IDs
Ziel: wir möchten auf eine externe API zugreifen, z. B. die Futurama-API, und uns Charaktere zurückgeben lassen.
- 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)
- beim Erstellen eines neuen Projekts mit Spring neben Spring Web auch Spring Reactive Web auswählen
- wir benötigen:
GET https://localhost:8080//api/futurama entgegennimmt, z. B. vom Postman, und sie an den Service weiterleitet
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.
- GET-Mapping ruft Methode des Service auf

- 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

- Dependency in die pom.xml einbinden:
- wir schreiben eine Methode, die uns einen Charakter zurückgeben soll

- 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


- 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:

- 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
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())
- erstellen wir zunächst eine String-Variable mit dem Namen responseBody, in die wir das Ergebnis unseres Post-Requests speichern.
- sorgen wir dafür, dass das Ergebnis des Post-Requests auch wirklich als String gespeichert wird.
- erstellen wir einen Object-Mapper.
- nutzen wir den Object-Mapper, um unseren String responseBody, der im JSON-Format vorliegt, in ein Java-Object vom Typ Order zu konvertieren.
- 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);
}
}