From 42c004bfd91cc24f61c21a6f135f311e18a613ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Fri, 14 Apr 2023 15:18:22 +0200
Subject: [PATCH 1/6] added Question Tests

---
 .../question/QuestionController.java          |   7 +
 .../question/QuestionFacade.java              |  21 +-
 .../question/QuestionRepository.java          |  10 +
 .../question/QuestionService.java             |   7 +
 .../moduleexercise/question/QuestionTest.java | 179 +++++++++++-------
 5 files changed, 157 insertions(+), 67 deletions(-)

diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java
index 1595f03f..531f6e74 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionController.java
@@ -139,4 +139,11 @@ public class QuestionController {
         questionFacade.delete(id);
         return ResponseEntity.noContent().build();
     }
+
+    //    @TestOnly
+    @DeleteMapping("/reset")
+    public void resetTable() {
+        questionFacade.resetTable();
+    }
+
 }
\ No newline at end of file
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
index bf6f97d1..aabf8116 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
@@ -91,8 +91,9 @@ public class QuestionFacade {
         for (var answer : answers) {
             answer.setQuestion(createdQuestion);
         }
-
-        return questionMapper.toDto(createdQuestion);
+        var result = questionMapper.toDto(createdQuestion);
+        result.setExerciseId(exercise.getId());
+        return result;
     }
 
     /**
@@ -104,9 +105,14 @@ public class QuestionFacade {
     public QuestionDto update(long id, QuestionUpdateDto dto) {
         Question question = questionMapper.fromUpdateDto(dto);
         question.setId(id);
+        var qston = questionService.find(id);
         List<Answer> questionAnswers = answerService.findAllByQuestionId(id);
         question.setAnswers(new HashSet<>(questionAnswers));
+
+        question.setExercise(qston.getExercise());
         Question updatedQuestion = questionService.update(question);
+        var ddto = questionMapper.toDto(updatedQuestion);
+
         return questionMapper.toDto(updatedQuestion);
     }
 
@@ -122,4 +128,15 @@ public class QuestionFacade {
         }
         questionService.delete(id);
     }
+
+    //@TestOnly
+    public void reset() {
+        questionService.reset();
+        questionService.resetId();
+    }
+
+    public void resetTable() {
+        questionService.reset();
+        questionService.resetId();
+    }
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionRepository.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionRepository.java
index b5b2adc4..0c11e6ec 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionRepository.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionRepository.java
@@ -1,11 +1,21 @@
 package org.fuseri.moduleexercise.question;
 
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * A repository interface for managing Question entities
  */
 @Repository
 public interface QuestionRepository extends JpaRepository<Question, Long> {
+
+    //@TestOnly
+    @Modifying
+    @Transactional
+    @Query( value = "ALTER TABLE Question ALTER COLUMN id RESTART WITH 1",nativeQuery = true)
+    void resetId();
+
 }
\ No newline at end of file
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionService.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionService.java
index 2d54e3d1..58171014 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionService.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionService.java
@@ -43,4 +43,11 @@ public class QuestionService extends DomainService<Question> {
         return repository.findById(id)
                 .orElseThrow(() -> new EntityNotFoundException("Question '" + id + "' not found."));
     }
+
+    //@TestOnly
+    @Transactional
+    public void resetId() {
+        repository.resetId();
+    }
+
 }
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
index c248a763..5155e64a 100644
--- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
@@ -1,22 +1,29 @@
 package org.fuseri.moduleexercise.question;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.fuseri.model.dto.exercise.AnswerDto;
 import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto;
 import org.fuseri.model.dto.exercise.ExerciseCreateDto;
-import org.fuseri.model.dto.exercise.ExerciseDto;
 import org.fuseri.model.dto.exercise.QuestionCreateDto;
 import org.fuseri.model.dto.exercise.QuestionDto;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
 
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
 import java.util.List;
 
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 
@@ -38,109 +45,151 @@ public class QuestionTest {
         }
     }
 
-    @Test
-    void testCreateQuestion() throws Exception {
-        long id = createExercise();
-        var answr = new AnswerDto("dis a logical paradox", true);
-        QuestionDto res = createQuestion(id);
-        var expected = new QuestionDto();
-        expected.setAnswers(List.of(answr));
-        expected.setExerciseId(id);
-        expected.setId(res.getId());
-        expected.setText("this statement is false");
-
-//        assert expected.equals(res);
+    private void createExercise() {
+        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0L);
+        var postExercise2 = new ExerciseCreateDto("riddles", "simple english riddles", 2, 0L);
+        try {
+            mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON));
+            mockMvc.perform(post("/exercises").content(asJsonString(postExercise2)).contentType(MediaType.APPLICATION_JSON));
+
+        } catch (Exception e) {
+            assert (false);
+        }
     }
 
-    private QuestionDto createQuestion(long id) throws Exception {
+    @BeforeEach
+    void init() {
+        createExercise();
+        long id = 2;
+
         var question = new QuestionCreateDto("this statement is false", id, List.of(new AnswerInQuestionCreateDto("dis a logical paradox", true)));
+        var question2 = new QuestionCreateDto("What month of the year has 28 days?", id, List.of(new AnswerInQuestionCreateDto("February", false), new AnswerInQuestionCreateDto("All of them", true)));
+        ResultActions posted = null;
+        try {
+            posted = mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
+            posted = mockMvc.perform(post("/questions").content(asJsonString(question2)).contentType(MediaType.APPLICATION_JSON));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
 
+    @AfterEach
+    void cleanup() {
+        try {
+            mockMvc.perform(delete("/questions/reset"));
+            mockMvc.perform(delete("/exercises/reset"));
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
 
+    @Test
+    void testCreateQuestion() throws Exception {
+        var exerciseId = 1L;
+        var question = new QuestionCreateDto("what is the meaning of: costs an arm and leg", exerciseId, List.of(new AnswerInQuestionCreateDto("dis very expencive", true), new AnswerInQuestionCreateDto("FMA refference", false)));
         var posted = mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
 
-
-        var cont = posted.andReturn().getResponse().getContentAsString();
-        var res = objectMapper.readValue(cont, QuestionDto.class);
-        return res;
+        posted.andExpect(status().isCreated())
+                .andExpect(jsonPath("$.text", is("what is the meaning of: costs an arm and leg")))
+                .andExpect(jsonPath("$.exerciseId", is(exerciseId)))
+                .andExpect(jsonPath("$.answers[0].text", is("dis very expencive")));
     }
 
-    private long createExercise() {
-        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0L);
-
-        long id = 0L;
-
-        try {
-            var dis = mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON));
-            var ok = dis.andReturn().getResponse().getContentAsString();
+    @Test
+    void testCreateQuestionEmptyQuestions() throws Exception {
+        var prompt = """
+                {
+                "text": "this is a question without exercise Id",
+                "exerciseId": 1,
+                "answers": []
+                }
+                """;
 
-            var ll = objectMapper.readValue(ok, ExerciseDto.class);
+        var posted = mockMvc.perform(post("/questions").content(prompt).contentType(MediaType.APPLICATION_JSON));
 
-            id = ll.getId();
-        } catch (Exception e) {
-            assert (false);
-        }
-        return id;
+        posted.andExpect(status().isCreated());
     }
 
 
     @Test
-    void getQuestion() throws Exception {
-
+    void testCreateQuestionEmptyField() throws Exception {
+        var exerciseId = 1L;
+        var question = new QuestionCreateDto("", exerciseId, List.of(new AnswerInQuestionCreateDto("dis very expencive", true), new AnswerInQuestionCreateDto("FMA refference", false)));
+        var posted = mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
 
-        long exerciseId = createExercise();
-        var question = createQuestion(exerciseId);
+        posted.andExpect(status().is4xxClientError());
+    }
 
-        var theId = String.format("/questions/%s", question.getId());
+    @Test
+    void testCreateQuestionMissingField() throws Exception {
+        var prompt = """
+                {
+                "text": "this is a question without exercise Id,
+                "answers" : []
+                }
+                """;
 
+        var posted = mockMvc.perform(post("/questions").content(prompt).contentType(MediaType.APPLICATION_JSON));
 
-        var gets = mockMvc.perform(get(theId));
+        posted.andExpect(status().is4xxClientError());
+    }
 
-        var content = gets.andReturn().getResponse().getContentAsString();
-        var res = objectMapper.readValue(content, QuestionDto.class);
+    private QuestionDto createQuestion(long id) throws Exception {
+        var question = new QuestionCreateDto("this statement is false", id, List.of(new AnswerInQuestionCreateDto("dis a logical paradox", true)));
+        var posted = mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
+        var cont = posted.andReturn().getResponse().getContentAsString();
+        var res = objectMapper.readValue(cont, QuestionDto.class);
+        return res;
+    }
 
-        assert res.equals(question);
 
+    @Test
+    void getQuestion() throws Exception {
+        var gets = mockMvc.perform(get("/questions/1"));
+        gets.andExpect(status().isOk()).andExpect(jsonPath("$.text", is("this statement is false")));
     }
 
     @Test
-    void getAnswer() throws Exception {
-        var exerciseId = createExercise();
-        var question = createQuestion(exerciseId);
-
-        var gets = mockMvc.perform(get(String.format("/questions/%s/answers", question.getId())));
+    void getQuestionNotFound() throws Exception {
+        var gets = mockMvc.perform(get("/questions/9999"));
+        gets.andExpect(status().isNotFound());
+    }
 
-        var content2 = gets.andReturn().getResponse().getContentAsString();
 
-        var res = objectMapper.readValue(content2, new TypeReference<List<AnswerDto>>() {
-        });
+    @Test
+    void getAnswer() throws Exception {
+        var gets = mockMvc.perform(get("/questions/2/answers"));
+        gets.andExpect(status().isOk())
+                .andExpect(jsonPath("$[0].text", is("February")))
+                .andExpect(jsonPath("$[1].text", is("All of them")));
 
-        assert (res.equals(question.getAnswers()));
 
     }
 
     @Test
     void TestUpdate() throws Exception {
-        long id = createExercise();
-        var question = createQuestion(id);
+        long id = 1;
 
         var updated = """
                 {
                   "text": "wat a paradox?",
-                  "exerciseId": "%s"
+                  "exerciseId": "1"
                 }
                 """;
 
-        updated = String.format(updated, id);
-//
-//        var smth = mockMvc.perform(put(String.format("/questions/%s", question.getId())).content(updated).contentType(MediaType.APPLICATION_JSON));
-//
-//        var content = smth.andReturn().getResponse().getContentAsString();
-
-//        var res = objectMapper.readValue(content, QuestionDto.class);
+        var gets = mockMvc.perform(put("/questions/1").content(updated).contentType(MediaType.APPLICATION_JSON));
 
-//        question.setText("wat a paradox?");
-
-//        assert (question.equals(res));
+        gets.andExpect(status().isOk())
+                .andExpect(jsonPath("$.text", is("wat a paradox?")));
+    }
 
+@Test
+    void deleteExisting() {
+    try {
+        mockMvc.perform(delete("/questions/1")).andExpect(status().isNoContent());
+    } catch (Exception e) {
+        throw new RuntimeException(e);
     }
 }
+
+}
-- 
GitLab


From 44a1247a03facd8280022538f6488d6fb56a7cee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Fri, 14 Apr 2023 15:18:45 +0200
Subject: [PATCH 2/6] added Exercise Tests

---
 .../moduleexercise/common/DomainService.java  |   5 +
 .../exercise/ExerciseController.java          |   6 +
 .../exercise/ExerciseFacade.java              |   5 +
 .../exercise/ExerciseRepository.java          |  14 +
 .../exercise/ExerciseService.java             |   5 +
 .../moduleexercise/exercise/ExerciseTest.java | 244 +++++++++++++++---
 6 files changed, 242 insertions(+), 37 deletions(-)

diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/common/DomainService.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/common/DomainService.java
index ec9d9681..1ce61dc3 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/common/DomainService.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/common/DomainService.java
@@ -52,4 +52,9 @@ public abstract class DomainService<T extends DomainObject> {
     public void delete(long id) {
         getRepository().deleteById(id);
     }
+
+    public void reset() {
+        getRepository().deleteAll();
+//        getRepository().id/
+    }
 }
\ No newline at end of file
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java
index f8d6926a..962d1556 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseController.java
@@ -173,4 +173,10 @@ public class ExerciseController {
         return ResponseEntity.noContent().build();
     }
 
+//    @TestOnly
+    @DeleteMapping("/reset")
+    public void resetTable() {
+        facade.resetTable();
+    }
+
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseFacade.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseFacade.java
index 8d9174a5..ef50a6d1 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseFacade.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseFacade.java
@@ -119,4 +119,9 @@ public class ExerciseFacade {
     public void delete(long id) {
         exerciseService.delete(id);
     }
+
+    public void resetTable() {
+        exerciseService.reset();
+        exerciseService.resetId();
+    }
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
index abdc8f01..cd0eba8d 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
@@ -5,9 +5,11 @@ import org.fuseri.moduleexercise.question.Question;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * A repository interface for managing Exercise entities
@@ -30,4 +32,16 @@ public interface ExerciseRepository extends JpaRepository<Exercise, Long> {
 
     @Query("SELECT q FROM Exercise e JOIN e.questions q WHERE e.id = :exerciseId")
     Page<Question> getQuestions(PageRequest pageRequest, @Param("exerciseId") Long exerciseId);
+
+    @Modifying
+    @Transactional
+    @Query(value = "TRUNCATE Table exercise",nativeQuery = true)
+    void resetTable();
+
+    @Modifying
+    @Transactional
+    @Query( value = "ALTER TABLE Exercise ALTER COLUMN id RESTART WITH 1",nativeQuery = true)
+    void resetId();
+
+
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseService.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseService.java
index 6d819b68..4aeed17d 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseService.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseService.java
@@ -85,4 +85,9 @@ public class ExerciseService extends DomainService<Exercise> {
                 PageRequest.of(page, DomainService.DEFAULT_PAGE_SIZE),
                 exerciseId);
     }
+
+    @Transactional
+    public void resetId() {
+        repository.resetId();
+    }
 }
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
index 92481d50..796b225e 100644
--- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
@@ -5,20 +5,20 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.fuseri.model.dto.common.Result;
 import org.fuseri.model.dto.exercise.ExerciseCreateDto;
 import org.fuseri.model.dto.exercise.ExerciseDto;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
-
-import java.util.Map;
-
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 
 
@@ -38,59 +38,122 @@ public class ExerciseTest {
         }
     }
 
+    private ExerciseCreateDto exercise1;
+    private ExerciseCreateDto exercise2;
+    private ExerciseCreateDto exercise3;
 
-    @Test
-    void getExercise() {
-        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0L);
-
-        long id = 0L;
 
+    @BeforeEach
+    void init() {
+        exercise1 = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0);
+        exercise2 = new ExerciseCreateDto("idioms1", "exercise on intermediate idioms", 2, 0);
+        exercise3 = new ExerciseCreateDto("idioms2", "exercise on basic idioms", 1, 0L);
         try {
-            var dis = mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON));
-            var ok = dis.andReturn().getResponse().getContentAsString();
-
-            var ll = objectMapper.readValue(ok, ExerciseDto.class);
-
-            id = ll.getId();
+            mockMvc.perform(post("/exercises").content(asJsonString(exercise1)).contentType(MediaType.APPLICATION_JSON));
+            mockMvc.perform(post("/exercises").content(asJsonString(exercise2)).contentType(MediaType.APPLICATION_JSON));
+            mockMvc.perform(post("/exercises").content(asJsonString(exercise3)).contentType(MediaType.APPLICATION_JSON));
         } catch (Exception e) {
             assert (false);
         }
+    }
 
+    @AfterEach
+    void cleanup() {
+
+        try {
+            mockMvc.perform(delete("/exercises/reset"));
+            } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
 
+    @Test
+    void getExercise() {
+        long id = 1L;
         try {
             var theId = String.format("/exercises/%s", id);
             var smth = mockMvc.perform(get(theId));
+            smth.andExpect(status().isOk())
+                    .andExpect(jsonPath("$.name", is(exercise1.getName())))
+                    .andExpect(jsonPath("$.description", is(exercise1.getDescription())))
+                    .andExpect(jsonPath("$.courseId", is((int) exercise1.getCourseId())))
+                    .andExpect(jsonPath("$.difficulty", is(exercise1.getDifficulty())));
+        } catch (Exception e) {
+            //do absolutely nothing
+        }
+    }
 
+    @Test
+    void deleteExercise() {
+        long id = 1L;
+        try {
+            var theId = String.format("/exercises/%s", id);
+            var smth = mockMvc.perform(delete(theId));
+            smth.andExpect(status().isNoContent());
         } catch (Exception e) {
             //do absolutely nothing
         }
     }
 
     @Test
-    void getFiltered() {
+    void deleteExercise_notFound() {
+        long id = 999999L;
+        try {
+            var theId = String.format("/exercises/%s", id);
+            var smth = mockMvc.perform(delete(theId));
+            smth.andExpect(status().isNoContent());
+        } catch (Exception e) {
+            //do absolutely nothing
+        }
+    }
 
 
-        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 0, 0L);
-        var postExercise1 = new ExerciseCreateDto("idioms1", "exercise on basic idioms", 0, 0L);
-        var postExercise2 = new ExerciseCreateDto("idioms2", "exercise on basic idioms", 1, 0L);
+    @Test
+    void getExercise_notFound() {
+        long id = 999999L;
+        try {
+            var theId = String.format("/exercises/%s", id);
+            var smth = mockMvc.perform(get(theId));
+            smth.andExpect(status().isNotFound());
+        } catch (Exception e) {
+            //do absolutely nothing
+        }
+    }
+
 
+    @Test
+    void FindAll() {
         try {
-            var exercise1 = mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON));
+            var dis = mockMvc.perform(get("/exercises").param("page", "0"));
+
+            dis.andExpect(status().isOk())
+                    .andExpect(jsonPath("$.total", is(3)))
+                    .andExpect(jsonPath("$.items[0].name", is(exercise1.getName())))
+                    .andExpect(jsonPath("$.items[0].description", is(exercise1.getDescription())))
+                    .andExpect(jsonPath("$.items[0].difficulty", is(exercise1.getDifficulty())))
+                    .andExpect(jsonPath("$.items[0].courseId", is((int) exercise1.getCourseId())))
+                    .andExpect(jsonPath("$.items[1].name", is(exercise2.getName())))
+                    .andExpect(jsonPath("$.items[1].description", is(exercise2.getDescription())))
+                    .andExpect(jsonPath("$.items[1].difficulty", is(exercise2.getDifficulty())))
+                    .andExpect(jsonPath("$.items[1].courseId", is((int) exercise2.getCourseId())))
+                    .andExpect(jsonPath("$.items[2].name", is(exercise3.getName())))
+                    .andExpect(jsonPath("$.items[2].description", is(exercise3.getDescription())))
+                    .andExpect(jsonPath("$.items[2].difficulty", is(exercise3.getDifficulty())))
+                    .andExpect(jsonPath("$.items[2].courseId", is((int) exercise3.getCourseId())));
 
-            var exercise2 = mockMvc.perform(post("/exercises").content(asJsonString(postExercise1)).contentType(MediaType.APPLICATION_JSON));
-            var exercise3 = mockMvc.perform(post("/exercises").content(asJsonString(postExercise2)).contentType(MediaType.APPLICATION_JSON));
         } catch (Exception e) {
-            //do absolutly nothing
+            throw new RuntimeException(e);
         }
 
 
-        Map<String, String> params;
+    }
 
-        try {
-            var filtered = mockMvc.perform(get("/exercises/filter").param("page", "0").param("courseId", "0").param("difficulty", "0"));
+    @Test
+    void getFiltered() {
 
+        try {
+            var filtered = mockMvc.perform(get("/exercises/filter").param("page", "0").param("courseId", "0").param("difficulty", "2"));
             var content = filtered.andReturn().getResponse().getContentAsString();
-
             var res = objectMapper.readValue(content, new TypeReference<Result<ExerciseDto>>() {
             });
 
@@ -102,11 +165,7 @@ public class ExerciseTest {
 
 //    @Test
 //    void getByExercise() throws Exception {
-//
-//        var exerciseId = createExercise();
-//        var question = createQuestion(exerciseId);
-//
-//        var theId = String.format("/questions/exercise/%s", exerciseId);
+//        var theId = String.format("/questions/exercise/%s", 9);
 //
 //        var smth = mockMvc.perform(get(theId).param("page", "0"));
 //
@@ -115,24 +174,94 @@ public class ExerciseTest {
 //        var res = objectMapper.readValue(content, new TypeReference<Result<QuestionDto>>() {
 //        });
 //
-//        Map<String, String> params;
 //
-//        assert (res.getItems().get(0).equals(question));
+//
+////        assert (res.getItems().get(0).equals(question));
 //    }
 
     @Test
     void testCreateExercise() throws Exception {
-        var expectedResponse = new ExerciseDto();
         var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0L);
 
-        mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()).andExpect(jsonPath("$.name").value("idioms")).andExpect(jsonPath("$.description").value("exercise on basic idioms")).andExpect(jsonPath("$.difficulty").value(2)).andExpect(jsonPath("$.courseId").value("0")).andReturn().getResponse().getContentAsString();
+        mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isCreated())
+                .andExpect(jsonPath("$.name").value("idioms"))
+                .andExpect(jsonPath("$.description").value("exercise on basic idioms"))
+                .andExpect(jsonPath("$.difficulty").value(2))
+                .andExpect(jsonPath("$.courseId").value("0")).andReturn().getResponse().getContentAsString();
     }
 
+    @Test
+    void testCreateExerciseEmptyBody() throws Exception {
+        var postExercise = "";
+
+        mockMvc.perform(post("/exercises").content((postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString();
+    }
+
+
+    @Test
+    void testCreateExerciseMissingDesc() throws Exception {
+        var postExercise = """
+                {
+                  "name": "idioms",
+                  "difficulty": 2,
+                  "courseId": 0,
+                }
+                """;
+
+        mockMvc.perform(post("/exercises").content((postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString();
+    }
+
+    @Test
+    void testCreateExerciseMissingName() throws Exception {
+        var postExercise = """
+                {
+                  "description: "exercise on basic idioms",
+                  "difficulty": 2,
+                  "courseId": 0,
+                }
+                """;
+
+        mockMvc.perform(post("/exercises").content((postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString();
+    }
+
+    @Test
+    void testCreateExerciseMissingDifficulty() throws Exception {
+        var postExercise = """
+                {
+                  "name": "idioms"
+                  "description: "exercise on basic idioms",
+                  "courseId": 0
+                }
+                """;
+
+        mockMvc.perform(post("/exercises").content((postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString();
+    }
+
+    @Test
+    void testCreateExerciseMissingCourseId() throws Exception {
+        var postExercise = """
+                {
+                  "name": "idioms"
+                  "description: "exercise on basic idioms",
+                  "difficulty": 0
+                }
+                """;
+
+        mockMvc.perform(post("/exercises").content((postExercise)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError()).andReturn().getResponse().getContentAsString();
+    }
+
+
     @Test
     void testUpdate() {
         var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0L);
 
-        long id = 0L;
+        long id = 1L;
 
         try {
             var dis = mockMvc.perform(post("/exercises").content(asJsonString(postExercise)).contentType(MediaType.APPLICATION_JSON));
@@ -178,4 +307,45 @@ public class ExerciseTest {
 
     }
 
+    @Test
+    void testUpdateNotFound() {
+        long id = 999999L;
+        var content = """
+                {
+                  "name": "idioms",
+                  "description": "exercise on basic idioms",
+                  "difficulty": 2,
+                  "courseId": 0
+                }
+                """;
+        try {
+            var theId = String.format("/exercises/%d", id);
+            mockMvc.perform(put(theId).content(content).contentType(MediaType.APPLICATION_JSON))
+                    .andExpect(status().isNotFound());
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    void testUpdateIncorrectBody() {
+        long id = 1L;
+        var content = """
+                {
+                  "description": "exercise on basic idioms",
+                  "difficulty": 2,
+                  "courseId": 0
+                }
+                """;
+        try {
+            var theId = String.format("/exercises/%d", id);
+            mockMvc.perform(put(theId).content(content).contentType(MediaType.APPLICATION_JSON))
+                    .andExpect(status().is4xxClientError());
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }
-- 
GitLab


From bcd260180a0374c6decc26f8dde7223f6d0c0cd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Fri, 14 Apr 2023 23:02:22 +0200
Subject: [PATCH 3/6] Created a test Only method and fixed update() method

---
 .../moduleexercise/answer/AnswerController.java  |  7 +++++++
 .../moduleexercise/answer/AnswerFacade.java      | 16 ++++++----------
 .../moduleexercise/answer/AnswerRepository.java  |  8 ++++++++
 .../moduleexercise/answer/AnswerService.java     |  4 ++++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java
index ebdc9cd6..f17cd187 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerController.java
@@ -96,4 +96,11 @@ public class AnswerController {
             return ResponseEntity.notFound().build();
         }
     }
+
+//    @TestOnly
+    @DeleteMapping("/reset")
+    public void resetTable() {
+        facade.resetTable();
+    }
+
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerFacade.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerFacade.java
index 370eed4b..da731cdb 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerFacade.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerFacade.java
@@ -70,17 +70,8 @@ public class AnswerFacade {
     public AnswerDto update(long id, AnswerCreateDto dto) {
         var updatedAnswer = mapper.fromCreateDto(dto);
         updatedAnswer.setId(id);
+        questionService.find(dto.getQuestionId());
         answerService.update(updatedAnswer);
-
-        Question question;
-        question = questionService.find(dto.getQuestionId());
-
-        var questionAnswers = question.getAnswers();
-        questionAnswers.removeIf(a -> a.getId() == id);
-        questionAnswers.add(updatedAnswer);
-        question.setAnswers(questionAnswers);
-        questionService.update(question);
-
         return mapper.toDto(updatedAnswer);
     }
 
@@ -101,4 +92,9 @@ public class AnswerFacade {
 
         answerService.delete(id);
     }
+
+    public void resetTable() {
+        answerService.reset();
+        answerService.resetId();
+    }
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerRepository.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerRepository.java
index 8d0844a8..f7221651 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerRepository.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerRepository.java
@@ -1,8 +1,11 @@
 package org.fuseri.moduleexercise.answer;
 
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
@@ -19,4 +22,9 @@ public interface AnswerRepository extends JpaRepository<Answer, Long> {
      * @return a list of all answers to the specified question
      */
     List<Answer> findByQuestionId(@Param("questionId") long questionId);
+
+    @Transactional
+    @Modifying
+    @Query( value = "ALTER TABLE Answer ALTER COLUMN id RESTART WITH 1",nativeQuery = true)
+    void reserId();
 }
\ No newline at end of file
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerService.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerService.java
index f5346fc5..f7883456 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerService.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/answer/AnswerService.java
@@ -58,4 +58,8 @@ public class AnswerService extends DomainService<Answer> {
         return repository.findById(id)
                 .orElseThrow(() -> new EntityNotFoundException("Answer '" + id + "' not found."));
     }
+
+    public void resetId() {
+        repository.reserId();
+    }
 }
-- 
GitLab


From 0ae68b088f31ff4cb7a174983734590cd0a161f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Fri, 14 Apr 2023 23:02:41 +0200
Subject: [PATCH 4/6] added some more tests

---
 .../moduleexercise/answer/AnswerTest.java     | 203 ++++++++++++------
 1 file changed, 138 insertions(+), 65 deletions(-)

diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerTest.java
index 46f2097e..86634c70 100644
--- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerTest.java
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerTest.java
@@ -1,14 +1,14 @@
 package org.fuseri.moduleexercise.answer;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.fuseri.model.dto.exercise.AnswerDto;
+import org.fuseri.model.dto.exercise.AnswerCreateDto;
 import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto;
 import org.fuseri.model.dto.exercise.AnswersCreateDto;
 import org.fuseri.model.dto.exercise.ExerciseCreateDto;
-import org.fuseri.model.dto.exercise.ExerciseDto;
 import org.fuseri.model.dto.exercise.QuestionCreateDto;
-import org.fuseri.model.dto.exercise.QuestionDto;
+import static org.hamcrest.Matchers.is;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@@ -16,8 +16,11 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 import java.util.List;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 @SpringBootTest
 @AutoConfigureMockMvc
@@ -28,6 +31,7 @@ public class AnswerTest {
     @Autowired
     private MockMvc mockMvc;
 
+
     public static String asJsonString(final Object obj) {
         try {
             return new ObjectMapper().writeValueAsString(obj);
@@ -36,120 +40,189 @@ public class AnswerTest {
         }
     }
 
-    private QuestionDto createQuestion(long id) throws Exception {
-        var question = new QuestionCreateDto("this statement is false", id,
+    @BeforeEach
+    void init() {
+        createExercise();
+        int exerciseId = 1;
+
+        var question = new QuestionCreateDto("this statement is false", exerciseId,
                 List.of(new AnswerInQuestionCreateDto("dis a logical paradox", true)));
+        var question2 = new QuestionCreateDto("What month of the year has 28 days?", exerciseId, List.of(new AnswerInQuestionCreateDto("February", false), new AnswerInQuestionCreateDto("All of them", true)));
 
+        try {
+            mockMvc.perform(post("/questions")
+                    .content(asJsonString(question))
+                    .contentType(MediaType.APPLICATION_JSON));
+            mockMvc.perform(post("/questions")
+                    .content(asJsonString(question2))
+                    .contentType(MediaType.APPLICATION_JSON));
 
-        var posted = mockMvc.perform(post("/questions")
-                .content(asJsonString(question))
-                .contentType(MediaType.APPLICATION_JSON));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @AfterEach
+    public void cleanup() {
+        try {
+            mockMvc.perform(delete("/answers/reset"));
+            mockMvc.perform(delete("/questions/reset"));
+            mockMvc.perform(delete("/exercises/reset"));
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
 
-        var cont = posted.andReturn().getResponse().getContentAsString();
-        var res = objectMapper.readValue(cont, QuestionDto.class);
-        return res;
+        }
     }
 
 
-    private long createExercise() {
-        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0);
 
-        long id = 0L;
+    private void createExercise() {
+        var postExercise = new ExerciseCreateDto("idioms", "exercise on basic idioms", 2, 0);
 
         try {
-            var dis = mockMvc.perform(post("/exercises")
+            mockMvc.perform(post("/exercises")
                     .content(asJsonString(postExercise))
                     .contentType(MediaType.APPLICATION_JSON));
-            var ok = dis.andReturn().getResponse().getContentAsString();
-
-            var ll = objectMapper.readValue(ok, ExerciseDto.class);
-
-            id = ll.getId();
         } catch (Exception e) {
-            assert (false);
+            throw new RuntimeException(e);
         }
-        return id;
     }
 
 
     @Test
     void testCreateAnswer() throws Exception {
 
-        List<AnswerDto> res = createAnswer();
+        var incorrect1 = new AnswerInQuestionCreateDto("True", false);
+        var incorrect2 = new AnswerInQuestionCreateDto("False", false);
 
-        var expected1 = new AnswerDto("True", false);
-        var expected2 = new AnswerDto("False", false);
+        var createAnswer = new AnswersCreateDto(1, List.of(incorrect1, incorrect2));
 
-        assert (res.get(0).equals(expected1));
-        assert (res.get(1).equals(expected2));
+        var posted = mockMvc.perform(post("/answers")
+                .content(asJsonString(createAnswer))
+                .contentType(MediaType.APPLICATION_JSON));
 
+        posted.andExpect(status().isCreated())
+                .andExpect(jsonPath("$[0].text",is("True")))
+                .andExpect(jsonPath("$[0].correct", is(false)))
+                .andExpect(jsonPath("$[1].text",is("False")))
+                .andExpect(jsonPath("$[1].correct",is(false)));
     }
 
-    private List<AnswerDto> createAnswer() throws Exception {
-        var exerciseId = createExercise();
-        var question = createQuestion(exerciseId);
 
-        var incorrect1 = new AnswerInQuestionCreateDto("True", false);
-        var incorrect2 = new AnswerInQuestionCreateDto("False", false);
+    @Test
+    void testCreateAnswerEmptyText() throws Exception {
 
-        var createAnswer = new AnswersCreateDto(question.getId(), List.of(incorrect1, incorrect2));
+        var incorrect1 = new AnswerInQuestionCreateDto("", false);
+
+        var createAnswer = new AnswersCreateDto(1, List.of(incorrect1));
 
         var posted = mockMvc.perform(post("/answers")
                 .content(asJsonString(createAnswer))
                 .contentType(MediaType.APPLICATION_JSON));
 
-        var asStr = posted.andReturn().getResponse().getContentAsString();
-
-        var res = objectMapper.readValue(asStr, new TypeReference<List<AnswerDto>>() {
-        });
-        return res;
+        posted.andExpect(status().is4xxClientError());
     }
 
     @Test
-    void testUpdate() throws Exception {
+    void testCreateAnswerMissingText() throws Exception {
 
-        var exerciseId = createExercise();
-        var question = createQuestion(exerciseId);
+        var prompt = """
+                {
+                "questionId": 1,
+                "answers": [
+                    {
+                    "text": "something",
+                    "correct": false
+                    }
+                ]
+                }
+                """;
 
-        var incorrect1 = new AnswerInQuestionCreateDto("True", false);
-        var incorrect2 = new AnswerInQuestionCreateDto("False", false);
+        var posted = mockMvc.perform(post("/answers")
+                .content(prompt)
+                .contentType(MediaType.APPLICATION_JSON));
 
+        posted.andExpect(status().isCreated());
+    }
 
-        var createAnswer = new AnswersCreateDto(question.getId(), List.of(incorrect1, incorrect2));
+    @Test
+    void testCreateAnswerMissingCorrect() throws Exception {
 
+        var prompt = """
+                {
+                "questionId": 1,
+                "answers": [
+                    {
+                    "text": "something"
+                    }
+                ]
+                }
+                """;
 
         var posted = mockMvc.perform(post("/answers")
-                .content(asJsonString(createAnswer))
+                .content(prompt)
                 .contentType(MediaType.APPLICATION_JSON));
 
-        var asStr = posted.andReturn().getResponse().getContentAsString();
+        posted.andExpect(status().isCreated());
+    }
 
-        var res = objectMapper.readValue(asStr, new TypeReference<List<AnswerDto>>() {
-        });
+    @Test
+    void testUpdate() throws Exception {
+        var updated = new AnswerCreateDto("dis true",false,1);
+        mockMvc.perform(put("/answers/1")
+                .content(asJsonString(updated)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.text",is("dis true")))
+                .andExpect(jsonPath("$.correct",is(false)));
+    }
 
+    @Test
+    void testUpdateNotFoundAnswer() throws Exception {
+        var updated = new AnswerCreateDto("dis true",false,1);
+        mockMvc.perform(put("/answers/9999")
+                        .content(asJsonString(updated)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isNotFound());
+    }
 
+    @Test
+    void testUpdateEmptyText() throws Exception {
+        var updated = new AnswerCreateDto("",false,1);
+        mockMvc.perform(put("/answers/1")
+                        .content(asJsonString(updated)).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError());
+    }
+
+    @Test
+    void testUpdateMissingField() throws Exception {
         var updated = """
                 {
-                  "text": "dis true",
-                  "correct": false,
-                  "questionId": "%s"
+                "correct": false,
+                "questionId": 1
                 }
                 """;
 
+        mockMvc.perform(put("/answers/1")
+                        .content(updated).contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().is4xxClientError());
+    }
 
-//        updated = String.format(updated, question.getId());
-//
-//        var puts = mockMvc.perform(put(String.format("/answers/%s", res.get(0).getId()))
-//                .content(updated).contentType(MediaType.APPLICATION_JSON));
-//
-//        var content = puts.andReturn().getResponse().getContentAsString();
-//
-//        var res2 = objectMapper.readValue(content, AnswerDto.class);
-//
-//        var expected = new AnswerDto("dis true", false);
-//
-//        assert res2.equals(expected);
-
+    @Test
+    void testDeleteExisting() {
+        try {
+            mockMvc.perform(delete("/answers/1"))
+                    .andExpect(status().isNoContent());
+        } catch (Exception e) {
+            assert(false);
+        }
     }
 
+    @Test
+    void testDeleteNotFound() {
+        try {
+            mockMvc.perform(delete("/answers/9999"))
+                    .andExpect(status().isNotFound());
+        } catch (Exception e) {
+            assert(false);
+        }
+    }
 }
-- 
GitLab


From bbdcb555faad742b78e8989bab649a57ba4e1f55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Fri, 14 Apr 2023 23:27:58 +0200
Subject: [PATCH 5/6] fixed exercise and question tests

---
 .../fuseri/moduleexercise/question/QuestionFacade.java |  2 +-
 .../fuseri/moduleexercise/exercise/ExerciseTest.java   |  2 ++
 .../fuseri/moduleexercise/question/QuestionTest.java   | 10 ++++------
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
index aabf8116..7e99230d 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/question/QuestionFacade.java
@@ -111,7 +111,7 @@ public class QuestionFacade {
 
         question.setExercise(qston.getExercise());
         Question updatedQuestion = questionService.update(question);
-        var ddto = questionMapper.toDto(updatedQuestion);
+
 
         return questionMapper.toDto(updatedQuestion);
     }
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
index 796b225e..30a025a3 100644
--- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseTest.java
@@ -61,7 +61,9 @@ public class ExerciseTest {
     void cleanup() {
 
         try {
+            mockMvc.perform(delete("/questions/reset"));
             mockMvc.perform(delete("/exercises/reset"));
+            mockMvc.perform(delete("/answers/reset"));
             } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
index 5155e64a..2a97bb21 100644
--- a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionTest.java
@@ -20,7 +20,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
@@ -66,8 +65,8 @@ public class QuestionTest {
         var question2 = new QuestionCreateDto("What month of the year has 28 days?", id, List.of(new AnswerInQuestionCreateDto("February", false), new AnswerInQuestionCreateDto("All of them", true)));
         ResultActions posted = null;
         try {
-            posted = mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
-            posted = mockMvc.perform(post("/questions").content(asJsonString(question2)).contentType(MediaType.APPLICATION_JSON));
+           mockMvc.perform(post("/questions").content(asJsonString(question)).contentType(MediaType.APPLICATION_JSON));
+           mockMvc.perform(post("/questions").content(asJsonString(question2)).contentType(MediaType.APPLICATION_JSON));
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -78,6 +77,7 @@ public class QuestionTest {
         try {
             mockMvc.perform(delete("/questions/reset"));
             mockMvc.perform(delete("/exercises/reset"));
+            mockMvc.perform(delete("/answers/reset"));
         } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
@@ -91,7 +91,7 @@ public class QuestionTest {
 
         posted.andExpect(status().isCreated())
                 .andExpect(jsonPath("$.text", is("what is the meaning of: costs an arm and leg")))
-                .andExpect(jsonPath("$.exerciseId", is(exerciseId)))
+                .andExpect(jsonPath("$.exerciseId", is((int)exerciseId)))
                 .andExpect(jsonPath("$.answers[0].text", is("dis very expencive")));
     }
 
@@ -168,8 +168,6 @@ public class QuestionTest {
 
     @Test
     void TestUpdate() throws Exception {
-        long id = 1;
-
         var updated = """
                 {
                   "text": "wat a paradox?",
-- 
GitLab


From 3e061fb0761a83188dcc62b3026000d4368a3153 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Gargalovi=C4=8D?= <xgargal@fi.muni.cz>
Date: Sun, 16 Apr 2023 14:31:12 +0200
Subject: [PATCH 6/6] added some more tests

---
 .../model/dto/exercise/ExerciseCreateDto.java |   1 -
 application/module-exercise/pom.xml           |   6 +
 .../exercise/ExerciseMapper.java              |  11 ++
 .../exercise/ExerciseRepository.java          |   4 -
 .../answer/AnswerFacadeTest.java              |  91 ++++++++++++++
 .../answer/AnswerRepositoryTest.java          | 101 +++++++++++++++
 .../answer/AnswerServiceTest.java             |  82 +++++++++++++
 .../exercise/ExerciseFacadeTest.java          | 106 ++++++++++++++++
 .../exercise/ExerciseRepositoryTest.java      | 106 ++++++++++++++++
 .../exercise/ExerciseServiceTest.java         | 115 ++++++++++++++++++
 .../question/QuestionFacadeTest.java          | 112 +++++++++++++++++
 .../question/QuestionRepositoryTest.java      |  88 ++++++++++++++
 .../question/QuestionServiceTest.java         |  66 ++++++++++
 13 files changed, 884 insertions(+), 5 deletions(-)
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerFacadeTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerRepositoryTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerServiceTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseFacadeTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseRepositoryTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseServiceTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionFacadeTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionRepositoryTest.java
 create mode 100644 application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionServiceTest.java

diff --git a/application/model/src/main/java/org/fuseri/model/dto/exercise/ExerciseCreateDto.java b/application/model/src/main/java/org/fuseri/model/dto/exercise/ExerciseCreateDto.java
index 21e7ee33..6d1cb1a7 100644
--- a/application/model/src/main/java/org/fuseri/model/dto/exercise/ExerciseCreateDto.java
+++ b/application/model/src/main/java/org/fuseri/model/dto/exercise/ExerciseCreateDto.java
@@ -9,7 +9,6 @@ import lombok.Getter;
 @AllArgsConstructor
 @Getter
 public class ExerciseCreateDto {
-
     @NotBlank
     private String name;
 
diff --git a/application/module-exercise/pom.xml b/application/module-exercise/pom.xml
index d42b3eae..0623aed0 100644
--- a/application/module-exercise/pom.xml
+++ b/application/module-exercise/pom.xml
@@ -44,6 +44,12 @@
             <version>0.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.fuseri</groupId>
+            <artifactId>sprachschulsystem</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseMapper.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseMapper.java
index 3c211aaa..3b44db86 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseMapper.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseMapper.java
@@ -1,9 +1,14 @@
 package org.fuseri.moduleexercise.exercise;
 
+import org.fuseri.model.dto.course.CourseDto;
 import org.fuseri.model.dto.exercise.ExerciseCreateDto;
 import org.fuseri.model.dto.exercise.ExerciseDto;
 import org.fuseri.moduleexercise.common.DomainMapper;
 import org.mapstruct.Mapper;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+
+import java.util.List;
 
 /**
  * Mapper between Exercises and their corresponding DTOs
@@ -18,4 +23,10 @@ public interface ExerciseMapper extends DomainMapper<Exercise, ExerciseDto> {
      * @return corresponding Exercise entity created from DTO
      */
     Exercise fromCreateDto(ExerciseCreateDto dto);
+
+    List<ExerciseDto> mapToList(List<Exercise> persons);
+
+    default Page<ExerciseDto> mapToPageDto(Page<Exercise> courses) {
+        return new PageImpl<>(mapToList(courses.getContent()), courses.getPageable(), courses.getTotalPages());
+    }
 }
diff --git a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
index cd0eba8d..6a4df023 100644
--- a/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
+++ b/application/module-exercise/src/main/java/org/fuseri/moduleexercise/exercise/ExerciseRepository.java
@@ -33,10 +33,6 @@ public interface ExerciseRepository extends JpaRepository<Exercise, Long> {
     @Query("SELECT q FROM Exercise e JOIN e.questions q WHERE e.id = :exerciseId")
     Page<Question> getQuestions(PageRequest pageRequest, @Param("exerciseId") Long exerciseId);
 
-    @Modifying
-    @Transactional
-    @Query(value = "TRUNCATE Table exercise",nativeQuery = true)
-    void resetTable();
 
     @Modifying
     @Transactional
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerFacadeTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerFacadeTest.java
new file mode 100644
index 00000000..af06853f
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerFacadeTest.java
@@ -0,0 +1,91 @@
+package org.fuseri.moduleexercise.answer;
+
+import org.fuseri.model.dto.exercise.AnswerCreateDto;
+import org.fuseri.model.dto.exercise.AnswerDto;
+import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto;
+import org.fuseri.model.dto.exercise.AnswersCreateDto;
+import org.fuseri.model.dto.exercise.QuestionUpdateDto;
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.fuseri.moduleexercise.question.Question;
+import org.fuseri.moduleexercise.question.QuestionService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import java.util.HashSet;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+public class AnswerFacadeTest {
+
+    private final Exercise exercise = new Exercise();
+    private final Question question = new Question("text",new HashSet<>(),exercise);
+
+
+    private final AnswerDto answerDto = new AnswerDto("name",true);
+
+    private final AnswerCreateDto answerCreateDto = new AnswerCreateDto("name",true,1L);
+    private final AnswerInQuestionCreateDto inQuestionCreateDto = new AnswerInQuestionCreateDto("name",true);
+    private final AnswersCreateDto answersCreateDto = new AnswersCreateDto(1L, List.of(inQuestionCreateDto));
+
+    private final QuestionUpdateDto questionUpdateDto = QuestionUpdateDto.builder().build();
+
+    private final Answer answer = new Answer("name",true,question);
+
+    @MockBean
+    AnswerRepository repository;
+    @Autowired
+    AnswerFacade facade;
+
+    @MockBean
+    AnswerService service;
+
+    @MockBean
+    QuestionService questionService;
+
+    @MockBean
+    AnswerMapper mapper;
+    @Test
+    void create() {
+        long id = 1;
+        when(service.find(id)).thenReturn(answer);
+        when(mapper.fromCreateDto(inQuestionCreateDto)).thenReturn(answer);
+        when(service.create(answer)).thenReturn(answer);
+        when(mapper.toDto(answer)).thenReturn(answerDto);
+        when(questionService.find(id)).thenReturn(question);
+        when(mapper.toDtoList(List.of(answer))).thenReturn(List.of(answerDto));
+
+        var actualDto = facade.createMultiple(answersCreateDto);
+
+        assertEquals(List.of(answerDto), actualDto);
+
+    }
+
+    @Test
+    void update() {
+        Long id = 1L;
+        when(repository.existsById(id)).thenReturn(true);
+        when(service.find(id)).thenReturn(answer);
+        when(mapper.fromCreateDto(answerCreateDto)).thenReturn(answer);
+        when(service.update(answer)).thenReturn(answer);
+        when(mapper.toDto(answer)).thenReturn(answerDto);
+        AnswerDto actualDto = facade.update(id,answerCreateDto);
+
+
+        assertEquals(answerDto, actualDto);
+    }
+    @Test
+    void testDelete() {
+        Long id = 1L;
+        when(service.find(id)).thenReturn(answer);
+        when(questionService.find(answer.getId())).thenReturn(question);
+        facade.delete(id);
+        verify(service).delete(id);
+    }
+
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerRepositoryTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerRepositoryTest.java
new file mode 100644
index 00000000..9a4179ea
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerRepositoryTest.java
@@ -0,0 +1,101 @@
+package org.fuseri.moduleexercise.answer;
+
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.fuseri.moduleexercise.exercise.ExerciseRepository;
+import org.fuseri.moduleexercise.question.Question;
+import org.fuseri.moduleexercise.question.QuestionRepository;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+
+@DataJpaTest
+public class AnswerRepositoryTest {
+
+    @Autowired
+    AnswerRepository repository;
+
+    @Autowired
+    QuestionRepository questionRepository;
+
+    @Autowired
+    ExerciseRepository exerciseRepository;
+
+    @Autowired
+    TestEntityManager entityManager;
+
+
+//    Question question = new Question("name","desc",2,1L,new HashSet<>());
+
+    Exercise exercise = new Exercise("name","desc",2,1L,new HashSet<>());
+
+    Question question = new Question("text",new HashSet<>(),exercise);
+
+    Answer answer = new Answer("text",false,question);
+    Answer answer2 = new Answer("text2",true,question);
+
+    @BeforeEach
+    void init() {
+        exerciseRepository.save(exercise);
+        questionRepository.save(question);
+    }
+
+    @Test
+    void saveQuestion() {
+        Question saved = questionRepository.save(question);
+
+        Assertions.assertNotNull(saved);
+        Assertions.assertEquals(question, saved);
+    }
+
+    @Test
+    void findById() {
+        entityManager.persist(answer);
+        entityManager.flush();
+
+        Answer found = repository.findById(answer.getId()).orElse(null);
+//        Question found = questionRepository.findById(question.getId()).orElse(null);
+
+        Assertions.assertNotNull(found);
+        Assertions.assertEquals(found, answer);
+    }
+
+
+    @Test
+    void testFindAllQuestions() {
+        entityManager.persist(answer);
+        entityManager.persist(answer2);
+
+        Page<Answer> coursePage = repository.findAll(PageRequest.of(0, 42));
+
+        Assertions.assertEquals(2, coursePage.getTotalElements());
+        Assertions.assertEquals(coursePage.getContent(), Arrays.asList(answer, answer2));
+    }
+
+
+    @Test
+    void testFindAllQuestionsEmpty() {
+        Page<Answer> coursePage = repository.findAll(PageRequest.of(0, 42));
+
+        Assertions.assertEquals(0, coursePage.getTotalElements());
+        Assertions.assertEquals(coursePage.getContent(), new ArrayList<>());
+    }
+
+    @Test
+    void testDeleteQuestion() {
+        Long id = entityManager.persist(answer).getId();
+        entityManager.flush();
+
+        questionRepository.deleteById(id);
+
+        Assertions.assertTrue(questionRepository.findById(id).isEmpty());
+    }
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerServiceTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerServiceTest.java
new file mode 100644
index 00000000..2c67bdc3
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/answer/AnswerServiceTest.java
@@ -0,0 +1,82 @@
+package org.fuseri.moduleexercise.answer;
+
+import jakarta.persistence.EntityNotFoundException;
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.fuseri.moduleexercise.question.Question;
+import org.fuseri.moduleexercise.question.QuestionRepository;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+public class AnswerServiceTest {
+    @MockBean
+    AnswerRepository repository;
+
+    @MockBean
+    QuestionRepository questionRepository;
+
+    @Autowired
+    AnswerService service;
+
+    Answer answer;
+    Question question;
+    Exercise exercise;
+
+    @BeforeEach
+    void setup() {
+        exercise = new Exercise("idioms", "exercise on basic idioms", 2, 1L, new HashSet<Question>());
+        question = new Question("text", new HashSet<>(), exercise);
+        answer = new Answer("text", false, question);
+    }
+
+
+    @Test
+    void create() {
+        when(repository.save(answer)).thenReturn(answer);
+        Answer result = service.create(answer);
+        Assertions.assertEquals(answer, result);
+        verify(repository).save(answer);
+    }
+
+    @Test
+    void notFound() {
+        when(repository.findById(anyLong())).thenReturn(Optional.empty());
+
+        Assertions.assertThrows(EntityNotFoundException.class, () -> service.find(anyLong()));
+    }
+
+    @Test
+    void find() {
+        when(repository.findById(anyLong())).thenReturn(Optional.of(answer));
+
+        Answer result = service.find(anyLong());
+
+        Assertions.assertEquals(answer, result);
+        verify(repository).findById(anyLong());
+    }
+
+    @Test
+    void findByQuestionId() {
+        long id = 1;
+        List<Answer> list = Collections.emptyList();
+
+        when(repository.existsById(id)).thenReturn(true);
+        when(repository.findByQuestionId(id)).thenReturn(list);
+        List<Answer> result = service.findAllByQuestionId(1L);
+
+        Assertions.assertEquals(list, result);
+        verify(repository).findByQuestionId(id);
+    }
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseFacadeTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseFacadeTest.java
new file mode 100644
index 00000000..d53519ac
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseFacadeTest.java
@@ -0,0 +1,106 @@
+package org.fuseri.moduleexercise.exercise;
+
+import org.fuseri.model.dto.common.Result;
+import org.fuseri.model.dto.exercise.ExerciseDto;
+import org.fuseri.model.dto.exercise.ExerciseCreateDto;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+public class ExerciseFacadeTest {
+
+    private final ExerciseDto exerciseDto = new ExerciseDto();
+
+    private final ExerciseCreateDto exerciseCreateDto = new ExerciseCreateDto("name","desc",2,1);
+
+    private final Exercise exercise = new Exercise();
+
+    @Autowired
+    ExerciseFacade facade;
+
+    @MockBean
+    ExerciseService service;
+
+    @MockBean
+    ExerciseMapper mapper;
+
+
+
+    @Test
+    void create() {
+
+        when(mapper.fromCreateDto(exerciseCreateDto)).thenReturn(exercise);
+        when(service.create(exercise)).thenReturn(exercise);
+        when(mapper.toDto(exercise)).thenReturn(exerciseDto);
+
+        ExerciseDto actualDto = facade.create(exerciseCreateDto);
+
+        assertEquals(exerciseDto, actualDto);
+
+    }
+
+    @Test
+    void testFindById() {
+        Long id = 0L;
+
+        when(service.find(id)).thenReturn(exercise);
+        when(mapper.toDto(exercise)).thenReturn(exerciseDto);
+
+        ExerciseDto actualDto = facade.find(id);
+
+        assertNotNull(actualDto);
+        assertEquals(exerciseDto, actualDto);
+    }
+
+
+    @Test
+    void testFindAll() {
+        int page = 0;
+        Pageable pageable = PageRequest.of(0, 10);
+        Page<Exercise> exercisePage = new PageImpl<>(List.of(exercise), pageable, 0);
+        Result<ExerciseDto> expectedPageDto = new Result<>();
+
+
+        when(service.findAll(page)).thenReturn(exercisePage);
+        when(mapper.toResult(exercisePage)).thenReturn(expectedPageDto);
+
+        Result<ExerciseDto> actualPageDto = facade.findAll(page);
+
+        assertEquals(expectedPageDto, actualPageDto);
+    }
+
+    @Test
+    void update() {
+        Long id = 1L;
+        when(mapper.fromCreateDto(exerciseCreateDto)).thenReturn(exercise);
+        when(service.update(exercise)).thenReturn(exercise);
+        when(mapper.toDto(exercise)).thenReturn(exerciseDto);
+
+        ExerciseDto actualDto = facade.update(id, exerciseCreateDto);
+
+        assertEquals(exerciseDto, actualDto);
+    }
+
+    @Test
+    void testDelete() {
+        Long id = 1L;
+        facade.delete(id);
+        verify(service).delete(id);
+    }
+
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseRepositoryTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseRepositoryTest.java
new file mode 100644
index 00000000..6d9187ed
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseRepositoryTest.java
@@ -0,0 +1,106 @@
+package org.fuseri.moduleexercise.exercise;
+
+import org.fuseri.moduleexercise.question.Question;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+
+@DataJpaTest
+class ExerciseRepositoryTest {
+
+    @Autowired
+    ExerciseRepository repository;
+
+    @Autowired
+    TestEntityManager entityManager;
+
+
+    Exercise exercise = new Exercise("name", "desc", 2, 1L, new HashSet<>());
+
+    Question question = new Question("text", new HashSet<>(), exercise);
+
+    @Test
+    void saveExercise() {
+        Exercise saved = repository.save(exercise);
+
+        Assertions.assertNotNull(saved);
+        Assertions.assertEquals(exercise, saved);
+    }
+
+    @Test
+    void findById() {
+        entityManager.persist(exercise);
+        entityManager.flush();
+
+        Exercise found = repository.findById(exercise.getId()).orElse(null);
+
+        Assertions.assertNotNull(found);
+        Assertions.assertEquals(found, exercise);
+    }
+
+
+    @Test
+    void filterPerDiffPerCourse() {
+        entityManager.persist(exercise);
+        entityManager.flush();
+
+        Page<Exercise> found = repository.filterPerDifficultyPerCourse(PageRequest.of(0, 10), 1L, 2);
+
+        Assertions.assertEquals(1, found.getTotalElements());
+        Assertions.assertEquals(found.getContent().get(0), exercise);
+    }
+
+    @Test
+    void testFindAllExercises() {
+        Exercise exercise1 = new Exercise();
+
+        entityManager.persist(exercise);
+        entityManager.persist(exercise1);
+
+        Page<Exercise> coursePage = repository.findAll(PageRequest.of(0, 42));
+
+        Assertions.assertEquals(2, coursePage.getTotalElements());
+        Assertions.assertEquals(coursePage.getContent(), Arrays.asList(exercise, exercise1));
+    }
+
+    @Test
+    void getQuestionsEmptyQuestions() {
+        entityManager.persist(exercise);
+
+        var result = repository.getQuestions(PageRequest.of(0, 10), 1L);
+
+        Assertions.assertEquals(0, result.getTotalElements());
+    }
+
+    @Test
+    void getQuestions() {
+        exercise.setQuestions(Set.of(question));
+        entityManager.persist(exercise);
+
+        var result = repository.getQuestions(PageRequest.of(0, 10), 1L);
+
+        Assertions.assertEquals(1, result.getTotalElements());
+        Assertions.assertEquals(result.getContent().get(0), question);
+    }
+
+    @Test
+    void testDeleteExercise() {
+        Long id = entityManager.persist(exercise).getId();
+        entityManager.flush();
+
+        repository.deleteById(id);
+
+        Assertions.assertTrue(repository.findById(id).isEmpty());
+    }
+
+
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseServiceTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseServiceTest.java
new file mode 100644
index 00000000..4624d554
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/exercise/ExerciseServiceTest.java
@@ -0,0 +1,115 @@
+package org.fuseri.moduleexercise.exercise;
+
+import jakarta.persistence.EntityNotFoundException;
+import org.fuseri.model.dto.exercise.ExerciseCreateDto;
+//import org.fuseri.modulelanguageschool.common.ResourceNotFoundException;
+
+import org.fuseri.model.dto.exercise.ExerciseDto;
+import org.fuseri.moduleexercise.question.Question;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+@SpringBootTest
+public class ExerciseServiceTest {
+
+    @MockBean
+    ExerciseRepository repository;
+
+    @Autowired
+    ExerciseService service;
+
+    Exercise exercise;
+    ExerciseCreateDto exercise2;
+    ExerciseCreateDto exercise3;
+
+    @BeforeEach
+    void setup() {
+        exercise = new Exercise("idioms", "exercise on basic idioms",2,1L,new HashSet<Question>());
+        exercise2 = new ExerciseCreateDto("idioms1", "exercise on intermediate idioms", 2, 0);
+        exercise3 = new ExerciseCreateDto("idioms2", "exercise on basic idioms", 1, 0L);
+    }
+
+
+    @Test
+    void create() {
+        when(repository.save(exercise)).thenReturn(exercise);
+        Exercise result = service.create(exercise);
+        Assertions.assertEquals(exercise, result);
+        verify(repository).save(exercise);
+    }
+
+    @Test
+    void notFound() {
+        when(repository.findById(anyLong())).thenReturn(Optional.empty());
+
+        Assertions.assertThrows(EntityNotFoundException.class, () -> service.find(anyLong()));
+    }
+
+    @Test
+    void find() {
+        when(repository.findById(anyLong())).thenReturn(Optional.of(exercise));
+
+        Exercise result = service.find(anyLong());
+
+        Assertions.assertEquals(exercise, result);
+        verify(repository).findById(anyLong());
+    }
+
+    @Test
+    void findAll() {
+        Pageable pageable = PageRequest.of(0, 10);
+        Page<Exercise> page = new PageImpl<>(Collections.emptyList(), pageable, 0);
+
+        when(repository.findAll(pageable)).thenReturn(page);
+        Page<Exercise> result = service.findAll(0);
+
+        Assertions.assertEquals(page, result);
+        verify(repository).findAll(pageable);
+    }
+
+    @Test
+    void findPerDiffPerCourse() {
+        PageRequest pageable = PageRequest.of(0, 10);
+        Page<Exercise> page = new PageImpl<>(Collections.emptyList(), pageable, 0);
+
+        when(repository.filterPerDifficultyPerCourse(pageable,1L,2)).thenReturn(page);
+
+        Page<Exercise> result = service.findPerDifficultyPerCourse(0,1L,2);
+
+        Assertions.assertEquals(page, result);
+        verify(repository).filterPerDifficultyPerCourse(pageable,1L,2);
+    }
+
+
+    @Test
+    void getQuestions() {
+        PageRequest pageable = PageRequest.of(0, 10);
+        Page<Question> page = new PageImpl<>(Collections.emptyList(), pageable, 0);
+
+        when(repository.getQuestions(pageable,1L)).thenReturn(page);
+        when(repository.existsById(1L)).thenReturn(true);
+
+
+        Page<Question> result = service.getQuestions(1L,0);
+
+        Assertions.assertEquals(page, result);
+        verify(repository).getQuestions(pageable,1L);
+    }
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionFacadeTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionFacadeTest.java
new file mode 100644
index 00000000..bf9cb27e
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionFacadeTest.java
@@ -0,0 +1,112 @@
+package org.fuseri.moduleexercise.question;
+
+
+import org.fuseri.model.dto.exercise.QuestionCreateDto;
+import org.fuseri.model.dto.exercise.QuestionDto;
+import org.fuseri.model.dto.exercise.QuestionUpdateDto;
+import org.fuseri.moduleexercise.answer.AnswerService;
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.fuseri.moduleexercise.exercise.ExerciseService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+public class QuestionFacadeTest {
+    private final QuestionDto questionDto = new QuestionDto();
+
+    private final QuestionCreateDto questionCreateDto = new QuestionCreateDto("name",1L,new ArrayList<>());
+
+    private final QuestionUpdateDto questionUpdateDto = QuestionUpdateDto.builder().build();
+
+    private final Exercise exercise = new Exercise();
+    private final Question question = new Question("text",new HashSet<>(),exercise);
+
+    @MockBean
+    QuestionRepository repository;
+    @Autowired
+    QuestionFacade facade;
+
+    @MockBean
+    QuestionService service;
+
+    @MockBean
+    AnswerService answerService;
+
+    @MockBean
+    QuestionMapper mapper;
+
+
+    @MockBean
+    ExerciseService exerciseService;
+//
+//    @MockBean
+//    QuestionMapper mapper;
+
+    @Test
+    void create() {
+        long id = 1;
+        when(exerciseService.find(id)).thenReturn(exercise);
+        when(mapper.fromCreateDto(questionCreateDto)).thenReturn(question);
+        when(service.create(question)).thenReturn(question);
+        when(mapper.toDto(question)).thenReturn(questionDto);
+
+        QuestionDto actualDto = facade.create(questionCreateDto);
+
+        assertEquals(questionDto, actualDto);
+
+    }
+
+    @Test
+    void testFindById() {
+        Long id = 0L;
+
+        when(service.find(id)).thenReturn(question);
+        when(mapper.toDto(question)).thenReturn(questionDto);
+
+        QuestionDto actualDto = facade.find(id);
+
+        assertNotNull(actualDto);
+        assertEquals(questionDto, actualDto);
+    }
+
+
+
+
+    @Test
+    void update() {
+        Long id = 1L;
+        when(repository.existsById(id)).thenReturn(true);
+//        when(repository.find)
+        when(service.find(id)).thenReturn(question);
+        when(mapper.fromCreateDto(questionCreateDto)).thenReturn(question);
+        when(service.update(question)).thenReturn(question);
+        when(mapper.toDto(question)).thenReturn(questionDto);
+        when(mapper.fromUpdateDto(questionUpdateDto)).thenReturn(question);
+        when(answerService.findAllByQuestionId(id)).thenReturn(Collections.emptyList());
+        QuestionDto actualDto = facade.update(id,questionUpdateDto);
+
+
+        assertEquals(questionDto, actualDto);
+    }
+
+    @Test
+    void testDelete() {
+        Long id = 1L;
+        when(service.find(id)).thenReturn(question);
+
+        facade.delete(id);
+        verify(service).delete(id);
+    }
+
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionRepositoryTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionRepositoryTest.java
new file mode 100644
index 00000000..3c0eb33e
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionRepositoryTest.java
@@ -0,0 +1,88 @@
+package org.fuseri.moduleexercise.question;
+
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.fuseri.moduleexercise.exercise.ExerciseRepository;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+
+@DataJpaTest
+public class QuestionRepositoryTest {
+
+    @Autowired
+    QuestionRepository repository;
+
+    @Autowired
+    ExerciseRepository exerciseRepository;
+
+    @Autowired
+    TestEntityManager entityManager;
+
+
+    Exercise exercise = new Exercise("name","desc",2,1L,new HashSet<>());
+
+    Question question = new Question("text",new HashSet<>(),exercise);
+    Question question2 = new Question("text2",new HashSet<>(),exercise);
+
+    @BeforeEach
+    void init() {
+        exerciseRepository.save(exercise);
+    }
+
+    @Test
+    void saveQuestion() {
+        Question saved = repository.save(question);
+
+        Assertions.assertNotNull(saved);
+        Assertions.assertEquals(question, saved);
+    }
+
+    @Test
+    void findById() {
+        entityManager.persist(question);
+        entityManager.flush();
+
+        Question found = repository.findById(question.getId()).orElse(null);
+
+        Assertions.assertNotNull(found);
+        Assertions.assertEquals(found, question);
+    }
+
+
+    @Test
+    void testFindAllQuestions() {
+        entityManager.persist(question);
+        entityManager.persist(question2);
+
+        Page<Question> coursePage = repository.findAll(PageRequest.of(0, 42));
+
+        Assertions.assertEquals(2, coursePage.getTotalElements());
+        Assertions.assertEquals(coursePage.getContent(), Arrays.asList(question, question2));
+    }
+    @Test
+    void testFindAllQuestionsEmpty() {
+        Page<Question> coursePage = repository.findAll(PageRequest.of(0, 42));
+
+        Assertions.assertEquals(0, coursePage.getTotalElements());
+        Assertions.assertEquals(coursePage.getContent(), new ArrayList<>());
+    }
+
+    @Test
+    void testDeleteQuestion() {
+        Long id = entityManager.persist(question).getId();
+        entityManager.flush();
+
+        repository.deleteById(id);
+
+        Assertions.assertTrue(repository.findById(id).isEmpty());
+    }
+}
diff --git a/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionServiceTest.java b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionServiceTest.java
new file mode 100644
index 00000000..e2085f85
--- /dev/null
+++ b/application/module-exercise/src/test/java/org/fuseri/moduleexercise/question/QuestionServiceTest.java
@@ -0,0 +1,66 @@
+package org.fuseri.moduleexercise.question;
+
+import jakarta.persistence.EntityNotFoundException;
+import org.fuseri.moduleexercise.exercise.Exercise;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import java.util.HashSet;
+import java.util.Optional;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+public class QuestionServiceTest {
+
+
+
+    @MockBean
+    QuestionRepository repository;
+
+    @Autowired
+    QuestionService service;
+
+    Exercise exercise;
+    Question question;
+    Question question1;
+
+    @BeforeEach
+    void setup() {
+        exercise = new Exercise("idioms", "exercise on basic idioms",2,1L,new HashSet<Question>());
+        question = new Question("text",new HashSet<>(),exercise);
+        question1 = new Question("text2",new HashSet<>(),exercise);
+    }
+
+
+    @Test
+    void create() {
+        when(repository.save(question)).thenReturn(question);
+        Question result = service.create(question);
+        Assertions.assertEquals(question, result);
+        verify(repository).save(question);
+    }
+
+    @Test
+    void notFound() {
+        when(repository.findById(anyLong())).thenReturn(Optional.empty());
+
+        Assertions.assertThrows(EntityNotFoundException.class, () -> service.find(anyLong()));
+    }
+
+    @Test
+    void find() {
+        when(repository.findById(anyLong())).thenReturn(Optional.of(question));
+
+        Question result = service.find(anyLong());
+
+        Assertions.assertEquals(question, result);
+        verify(repository).findById(anyLong());
+    }
+
+}
-- 
GitLab