> [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();
}
}
```