> [name=Martin. S] > [time=Thu, Apr 13, 2023] > [name=Lucas. C] > [time=Thu, Apr 13, 2023] > [name=Lukas. B] > [time=Thu, Apr 13, 2023] > [name=Linus. S] > [time=Thu, Apr 13, 2023] # Mockito ## 1. Grundlagen von Mockito: - ist eine Open-Source-Testframework für Java, das verwendet wird, um Mock-Objekte für Unit-Tests zu erstellen. - damit können Mock-Objekte erstellt werden, um externe Abhängigkeiten von Unit-Tests zu isolieren und Tests unabhängig und deterministisch zu gestalten. - ermöglicht das Definieren von Verhalten für Mock-Objekte, wie das Festlegen von Rückgabewerten, das Überprüfen von Methodenaufrufen und das Werfen von Ausnahmen. - bietet auch Funktionen zur Überprüfung von Verhalten, wie das Überprüfen von Methodenaufrufen und Argumenten. ## 2. Annotation bei Mockito: - **@Mock**: Diese Annotation wird verwendet, um ein Mock-Objekt zu erstellen. Es wird normalerweise für externe Abhängigkeiten verwendet, die in einem Unit-Test simuliert werden sollen. - **@Spy**: Diese Annotation wird verwendet, um ein Spy-Objekt zu erstellen. Ein Spy ist ein echtes Objekt, das jedoch überwacht wird und Methodenaufrufe und Rückgabewerte verfolgen kann. - **@Captor**: Diese Annotation wird verwendet, um Argumente zu erfassen, die an Mock-Objekte übergeben wurden, wenn Methoden auf ihnen aufgerufen wurden. Es ermöglicht das Überprüfen von Argumenten, die an Mock-Objekte übergeben wurden. - **@InjectMock**: Diese Annotation wird verwendet, um ein echtes Objekt zu erstellen, das Mock-Objekte injiziert, um die Abhängigkeiten des zu testenden Objekts zu steuern. ## 3. Unterschied zwischen @Mock und @Spy mit praktischem Beispiel: - @Mock erstellt ein vollständig simuliertes Objekt, das kein echtes Verhalten hat und nur definiertes Verhalten gemäß den Tests ausführt. - @Spy erstellt ein echtes Objekt, das jedoch überwacht wird und das tatsächliche Verhalten behält, es sei denn, es wird speziell durch Mockito-Anweisungen überschrieben. ### Praktisches Beispiel UserService Klasse ```java public class UserService { private UserRepository userRepository; // Konstruktor public UserService(UserRepository userRepository) { this.userRepository = userRepository; } // Methode, um einen neuen Benutzer zu speichern public void createUser(User user) { // Logik zur Erstellung eines Benutzers userRepository.save(user); } // Methode, um einen Benutzer anhand der ID abzurufen public User getUserById(int userId) { // Logik zur Abfrage eines Benutzers anhand der ID return userRepository.findById(userId); } } ``` UserService-Test mit **@Mock** ```java @RunWith(MockitoJUnitRunner.class) public class UserServiceTest { @Mock private UserRepository userRepositoryMock; // Mock-Objekt erstellen private UserService userService; @Before public void setUp() { MockitoAnnotations.initMocks(this); userService = new UserService(userRepositoryMock); } @Test public void testCreateUser() { User user = new User("John", "Doe"); userService.createUser(user); Mockito.verify(userRepositoryMock).save(user); // Überprüfen, ob die Methode save() mit dem richtigen User-Objekt aufgerufen wurde } @Test public void testGetUserById() { int userId = 1; User expectedUser = new User("John", "Doe"); Mockito.when(userRepositoryMock.findById(userId)).thenReturn(expectedUser); // Definieren des Rückgabewerts für die Methode findById() User actualUser = userService.getUserById(userId); assertEquals(expectedUser, actualUser); // Überprüfen, ob der zurückgegebene User dem erwarteten User entspricht } } ``` UserService-Test mit **@Spy** ```java @RunWith(MockitoJUnitRunner.class) public class UserServiceTest { @Spy private UserRepository userRepositorySpy; // Spy-Objekt erstellen private UserService userService; @Before public void setUp() { MockitoAnnotations.initMocks(this); userService = new UserService(userRepositorySpy); } @Test public void testCreateUser() { User user = new User("John", "Doe"); userService.createUser(user); Mockito.verify(userRepositorySpy).save(user); // Überprüfen, ob die Methode save() mit dem richtigen User-Objekt aufgerufen wurde } @Test public void testGetUserById() { int userId = 1; User expectedUser = new User("John", "Doe"); Mockito.when(userRepositorySpy.findById(userId)).thenReturn(expectedUser); // Definieren des Rückgabewerts für die Methode findById() User actualUser = userService ``` ## 4. Nutzen des Einsatzes von Mockito in den Unit Tests des Beispielprojektes: - Code kann mehrfach genutzt werden - Änderungen können einfacher durchegeführt werden - Bessere Übersicht ### Before Ohne die Benutzung von Mockito muss in jedem Test einzeln die Testdaten inizialisiert werden ```java @Test public void whenGetSortedShapesAsc_thenReturnCorrectAscSort() { // arrange ShapeSorter sorter = new ShapeSorter(); Rectangle rect1 = new Rectangle(0, 0, 10, 10); Rectangle rect2 = new Rectangle(0, 0, 20, 20); Rectangle rect3 = new Rectangle(0, 0, 15, 15); Rectangle rect4 = new Rectangle(0, 0, 5, 5); Rectangle rect5 = new Rectangle(0, 0, 12, 12); sorter.addShapeToSort(rect1); sorter.addShapeToSort(rect2); sorter.addShapeToSort(rect3); sorter.addShapeToSort(rect4); sorter.addShapeToSort(rect5); // act List<ShapeWithArea> result = sorter.getSortedShapesAsc(); // assert assertEquals(rect4.calculateArea(), result.get(0).calculateArea(), 0); assertEquals(rect1.calculateArea(), result.get(1).calculateArea(), 0); assertEquals(rect5.calculateArea(), result.get(2).calculateArea(), 0); assertEquals(rect3.calculateArea(), result.get(3).calculateArea(), 0); assertEquals(rect2.calculateArea(), result.get(4).calculateArea(), 0); } ``` ### After (With Mockito) Mit Mockitp werden die Testdaten einmal in einer Setup funktion inizialisiert. ```java @Mock ShapeWithArea shape1; @Mock ShapeWithArea shape2; @Mock ShapeWithArea shape3; @Mock ShapeWithArea shape4; @Mock ShapeWithArea shape5; @Spy ShapeSorter sorter; @BeforeEach public void setup() { // arrange sorter = spy(new ShapeSorter()); sorter.addShapeToSort(shape1); sorter.addShapeToSort(shape2); sorter.addShapeToSort(shape3); sorter.addShapeToSort(shape4); sorter.addShapeToSort(shape5); lenient().when(shape1.calculateArea()).thenReturn(100d); lenient().when(shape2.calculateArea()).thenReturn(400d); lenient().when(shape3.calculateArea()).thenReturn(225d); lenient().when(shape4.calculateArea()).thenReturn(25d); lenient().when(shape5.calculateArea()).thenReturn(144d); } ``` # Teil 2 Praxis :smiling_face_with_smiling_eyes_and_hand_covering_mouth: ## 1. & 2. 1. Ist vorbereitung für 2. Mockito optimiert den Test, indem es Argument Matchers verwendet, um flexible Erwartungen für Methodenaufrufe zu setzen und den Testcode weniger anfällig für Änderungen in den Argumenten zu machen. Ausserdem kann Mockito Verify verwenden, um sicherzustellen, dass bestimmte Methodenaufrufe mit den erwarteten Argumenten aufgerufen wurden. ## 3. Neuer Test mit @Mock und @Spy Annotations erstellt. ```java @RunWith(MockitoJUnitRunner.class) public class LanguageControllerTestMock { @Mock private LanguageRepository languageRepository; @InjectMocks private LanguageController languageController; @Spy private List<Language> languages = new LinkedList<>(); @Test public void testGetAllLanguages() { Language language1 = new Language("Englisch"); Language language2 = new Language("Spanisch"); languages.add(language1); languages.add(language2); Mockito.when(languageRepository.findAll()).thenReturn(languages); ResponseEntity<Iterable<Language>> response = languageController.getAllLanguages(); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).hasSize(2); assertThat(response.getBody()).contains(language1, language2); Mockito.verify(languageRepository).findAll(); } } ```