From 9008bdd026cd309da528c87d5164f924952861e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 14 Jan 2026 19:06:09 +0100 Subject: [PATCH 1/6] Ingredient Constructors for testing --- commons/src/main/java/commons/FormalIngredient.java | 7 +++++++ commons/src/main/java/commons/RecipeIngredient.java | 11 ++++++++--- commons/src/main/java/commons/VagueIngredient.java | 5 +++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/commons/src/main/java/commons/FormalIngredient.java b/commons/src/main/java/commons/FormalIngredient.java index 19f514c..88d713a 100644 --- a/commons/src/main/java/commons/FormalIngredient.java +++ b/commons/src/main/java/commons/FormalIngredient.java @@ -31,6 +31,13 @@ public class FormalIngredient extends RecipeIngredient implements Scalable Date: Wed, 14 Jan 2026 19:06:26 +0100 Subject: [PATCH 2/6] wiremock dependency --- client/pom.xml | 7 +++---- commons/pom.xml | 7 ------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 509f836..b9eb186 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -11,7 +11,6 @@ UTF-8 5.10.1 - 5.8.0 3.1.9 25.0.1 @@ -92,9 +91,9 @@ test - org.mockito - mockito-core - ${version.mockito} + org.wiremock + wiremock + 3.3.1 test diff --git a/commons/pom.xml b/commons/pom.xml index f48fbcf..0c4e972 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -11,7 +11,6 @@ UTF-8 5.10.1 - 5.8.0 @@ -39,12 +38,6 @@ ${version.junit} test - - org.mockito - mockito-core - ${version.mockito} - test - com.fasterxml.jackson.core jackson-databind From e4fd15b120eb2b7a9b4cda4f996506d794b146a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 14 Jan 2026 19:36:27 +0100 Subject: [PATCH 3/6] fixed weird spacing --- commons/src/test/java/commons/RecipeIngredientTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commons/src/test/java/commons/RecipeIngredientTest.java b/commons/src/test/java/commons/RecipeIngredientTest.java index b4b78bc..1e38682 100644 --- a/commons/src/test/java/commons/RecipeIngredientTest.java +++ b/commons/src/test/java/commons/RecipeIngredientTest.java @@ -9,7 +9,6 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; public class RecipeIngredientTest { - private Map ingredientUnitMap; private Map ingredientDescriptorMap; @@ -17,12 +16,14 @@ public class RecipeIngredientTest { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3); return new FormalIngredient(ingredient, 1.0, unit); } + private VagueIngredient getVague(String descriptor) { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3); return new VagueIngredient(ingredient, descriptor); } + @BeforeEach - void setup(){ + void setup() { ingredientUnitMap = new HashMap<>(); ingredientDescriptorMap = new HashMap<>(); List.of("g", "kg", "ml", "l", "tbsp", "cup") @@ -37,6 +38,7 @@ public class RecipeIngredientTest { FormalIngredient fi = new FormalIngredient(ingredient, 1.0, "g"); assertEquals(ingredient, fi.getIngredient()); } + @Test void testInstantiateVagueIngredient() { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3); From 33b73c44b8fb7ec9723cc9bedccad8a6a150891d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 14 Jan 2026 19:36:40 +0100 Subject: [PATCH 4/6] Wrong comment --- client/src/main/java/client/utils/ServerUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/client/utils/ServerUtils.java b/client/src/main/java/client/utils/ServerUtils.java index 101486a..113ed01 100644 --- a/client/src/main/java/client/utils/ServerUtils.java +++ b/client/src/main/java/client/utils/ServerUtils.java @@ -149,7 +149,7 @@ public class ServerUtils { //Get the recipe HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(SERVER + "/recipe/" + id)) - .GET() //Needs to be changed to POST() when api is changed + .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); From 443908e7b6e8e41cdee266cc8906725e9c4c52c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 14 Jan 2026 19:41:34 +0100 Subject: [PATCH 5/6] Tests with wiremock --- .../test/java/client/ServerUtilsMockTest.java | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 client/src/test/java/client/ServerUtilsMockTest.java diff --git a/client/src/test/java/client/ServerUtilsMockTest.java b/client/src/test/java/client/ServerUtilsMockTest.java new file mode 100644 index 0000000..369c48c --- /dev/null +++ b/client/src/test/java/client/ServerUtilsMockTest.java @@ -0,0 +1,280 @@ +package client; + +import client.utils.ServerUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import commons.FormalIngredient; +import commons.Ingredient; +import commons.Recipe; +import commons.RecipeIngredient; +import commons.VagueIngredient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.junit.jupiter.api.Assertions.*; + +@WireMockTest(httpPort = 8080) +class ServerUtilsMockTest { + private ServerUtils serverUtils; + private ObjectMapper objectMapper; + + static final List ingredients = List.of( + new Ingredient("Bread", 1, 2, 3), + new Ingredient("Cheese", 2, 2, 2), + new Ingredient("Ham", 3, 3, 3) + ); + + static final List testIngredients = List.of( + new VagueIngredient(ingredients.get(0), "2 pieces of"), + new VagueIngredient(ingredients.get(1), "1 slice of"), + new VagueIngredient(ingredients.get(2), "1 slice of") + ); + + static final List testPrepSteps = List.of("1. do smth", "2. do smth else"); + + @BeforeEach + void setup() { + objectMapper = new ObjectMapper(); + serverUtils = new ServerUtils(); + } + + /** + * Returns a deep copy of recipe, but with null as id. + * @param recipe recipe to be stripped of id. + * @return new recipe without id. + */ + Recipe stripId(Recipe recipe) { + Recipe newRecipe = new Recipe(); + newRecipe.setId(null); + newRecipe.setName(recipe.getName()); + newRecipe.setIngredients(recipe.getIngredients()); + newRecipe.setPreparationSteps(recipe.getPreparationSteps()); + return newRecipe; + } + + @Test + void addRecipeTest() throws IOException, InterruptedException { + Recipe input = new Recipe( + 1L, + "Eggs on toast", + "en", + testIngredients, + testPrepSteps); + + String inputJson = objectMapper.writeValueAsString(input); + + // Setup fake endpoint that returns empty list for getRecipes. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + // Setup fake endpoint that returns the input recipe when creating new recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(inputJson))); + + // The addRecipe should strip the recipe of id when sending to server. + Recipe verifyRecipe = stripId(input); + String verifyJson = objectMapper.writeValueAsString(verifyRecipe); + + Recipe result = serverUtils.addRecipe(input); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + assertNotNull(result); + assertEquals(1L, result.getId()); + assertEquals("Eggs on toast", result.getName()); + assertEquals(testIngredients, result.getIngredients()); + assertEquals(testPrepSteps, result.getPreparationSteps()); + } + + @Test + void addRecipeDuplicateTest() throws IOException, InterruptedException { + Recipe pre = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + // We start with name Steak already being taken. + List recipes = List.of(pre); + String recipesJson = objectMapper.writeValueAsString(recipes); + + // Setup fake endpoint that returns list with 1 recipe in it. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + // Our input to add. + Recipe inputRecipe = new Recipe( + 1337L, + pre.getName(), + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + + // addRecipe should generate this. + Recipe generatedRecipe = new Recipe( + null, + pre.getName()+"(1)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Server will return this. + Recipe serverReturnRecipe = new Recipe( + pre.getId()+1, + pre.getName()+"(1)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String serverReturnJson = objectMapper.writeValueAsString(serverReturnRecipe); + + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(serverReturnJson))); + + // Ignore the return value as it's tested in addRecipeTest. + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void addRecipeDoubleDuplicateTest() throws IOException, InterruptedException { + Recipe pre = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + // We start with name Steak already being taken. + List recipes = new ArrayList<>(List.of(pre)); + String recipesJson = objectMapper.writeValueAsString(recipes); + + // Setup fake endpoint that returns list with 1 recipe in it. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + // Our input to add. + Recipe inputRecipe = new Recipe( + 1337L, + pre.getName(), + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + + // addRecipe should generate this. + Recipe generatedRecipe = new Recipe( + null, + pre.getName()+"(2)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Doesn't matter what we return here, verifyJson is just convenient as it's a recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(verifyJson))); + + // Ignore the return value as it's tested in addRecipeTest. + serverUtils.addRecipe(inputRecipe); + + // update recipes + recipes.add(inputRecipe); + recipesJson = objectMapper.writeValueAsString(recipes); + inputRecipe.setName(pre.getName()); // Reset name back to Steak without the (1) + + // Setup fake endpoint that returns list with 2 recipes in it. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void addRecipeIngredientIdNullTest() throws IOException, InterruptedException { + // This test checks if RecipeIngredient and recipe ids are null. + Ingredient i1 = new Ingredient(1L, "salt",1,2,3); + Ingredient i2 = new Ingredient(2L, "pepper",4,5,6); + + // input + List ingredients = List.of( + new FormalIngredient(1L, i1, 40, "g"), + new FormalIngredient(2L, i2, 50, "g") + ); + + // generated + List ingredientsStripped = List.of( + new FormalIngredient(null, i1, 40, "g"), + new FormalIngredient(null, i2, 50, "g") + ); + + Recipe inputRecipe = new Recipe( + 1L, + "Steak", + "en", + ingredients, + testPrepSteps); + String inputJson = objectMapper.writeValueAsString(inputRecipe); + + Recipe generatedRecipe = new Recipe( + null, + "Steak", + "en", + ingredientsStripped, + testPrepSteps); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Setup fake endpoint that returns empty list for getRecipes. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + // Setup fake endpoint that returns the input recipe when creating new recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(inputJson))); + + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void findIdNotFoundTest() throws IOException, InterruptedException { + // Setup fake endpoint that returns empty list for getRecipes. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + assertThrows(IOException.class, () -> serverUtils.findId(1L)); + } + + @Test + void findIdFoundTest() throws IOException, InterruptedException { + Recipe recipe = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + String recipeJson = objectMapper.writeValueAsString(recipe); + + // Setup fake endpoint that returns the recipe by id. + stubFor(get(urlPathEqualTo("/api/recipe/"+recipe.getId())).willReturn(okJson(recipeJson))); + + Recipe found = serverUtils.findId(recipe.getId()); + + assertEquals(recipe.getId(), found.getId()); + assertEquals(recipe.getName(), found.getName()); + assertEquals(recipe.getIngredients(), found.getIngredients()); + assertEquals(recipe.getPreparationSteps(), found.getPreparationSteps()); + } + +} From 5ef14ae5eec0a606e00ba25c42e8e3f3669cee66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 14 Jan 2026 19:54:56 +0100 Subject: [PATCH 6/6] Improved comments --- client/src/test/java/client/ServerUtilsMockTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/test/java/client/ServerUtilsMockTest.java b/client/src/test/java/client/ServerUtilsMockTest.java index 369c48c..57e3e42 100644 --- a/client/src/test/java/client/ServerUtilsMockTest.java +++ b/client/src/test/java/client/ServerUtilsMockTest.java @@ -69,6 +69,7 @@ class ServerUtilsMockTest { String inputJson = objectMapper.writeValueAsString(input); // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); // Setup fake endpoint that returns the input recipe when creating new recipe. @@ -105,6 +106,7 @@ class ServerUtilsMockTest { String recipesJson = objectMapper.writeValueAsString(recipes); // Setup fake endpoint that returns list with 1 recipe in it. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); // Our input to add. @@ -158,6 +160,7 @@ class ServerUtilsMockTest { String recipesJson = objectMapper.writeValueAsString(recipes); // Setup fake endpoint that returns list with 1 recipe in it. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); // Our input to add. @@ -189,6 +192,7 @@ class ServerUtilsMockTest { inputRecipe.setName(pre.getName()); // Reset name back to Steak without the (1) // Setup fake endpoint that returns list with 2 recipes in it. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); serverUtils.addRecipe(inputRecipe); @@ -234,6 +238,7 @@ class ServerUtilsMockTest { String verifyJson = objectMapper.writeValueAsString(generatedRecipe); // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); // Setup fake endpoint that returns the input recipe when creating new recipe. @@ -250,6 +255,7 @@ class ServerUtilsMockTest { @Test void findIdNotFoundTest() throws IOException, InterruptedException { // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); assertThrows(IOException.class, () -> serverUtils.findId(1L)); @@ -267,6 +273,7 @@ class ServerUtilsMockTest { String recipeJson = objectMapper.writeValueAsString(recipe); // Setup fake endpoint that returns the recipe by id. + // urlPathEqualTo, because it ignores query params. stubFor(get(urlPathEqualTo("/api/recipe/"+recipe.getId())).willReturn(okJson(recipeJson))); Recipe found = serverUtils.findId(recipe.getId());