Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| de:modul:ffit:3-jahr:cicd:learningunits:lu06:a [2026/03/15 17:03] – apeter | de:modul:ffit:3-jahr:cicd:learningunits:lu06:a [2026/03/15 18:28] (aktuell) – apeter | ||
|---|---|---|---|
| Zeile 2: | Zeile 2: | ||
| Test Doubles sind Hilfsobjekte, | Test Doubles sind Hilfsobjekte, | ||
| + | In der folgenden Tabelle ist eine kleine Übersicht über verschiedene Test Doubles in aufsteigender Reihenfolge. Es ist grundsätzlich empfohlen, die einfachste (oberste) Variante zu wählen, die funktioniert. | ||
| - | Kleine Übersicht über verschiedene Test Doubles: | + | ^ Double-Typ ^ Beschreibung ^ Entscheidungsfrage ^ |
| - | | + | | Dummy | Platzhalter |
| - | | + | | Stub | Vordefinierte |
| - | | + | | Fake | Vereinfachte |
| - | | + | | Spy | Aufrufe beobachten |
| - | | + | | Mock | Überprüfung direkt bei Aufruf | Ist es sinnvoll, den Test bereits abzubrechen? |
| ==== Dummy ==== | ==== Dummy ==== | ||
| Zeile 30: | Zeile 31: | ||
| Dadurch ist ein '' | Dadurch ist ein '' | ||
| - | <code javascript></ | + | |
| + | <code javascript> | ||
| + | const userRepositoryStub = { | ||
| + | findUserById(id) { | ||
| + | return { id: 1, name: " | ||
| + | } | ||
| + | } | ||
| + | |||
| + | const service = new UserService(userRepositoryStub) | ||
| + | |||
| + | const user = service.getUser(1) | ||
| + | </ | ||
| + | In diesem Beispiel wird für die Id 1 immer das Alice-Testobjekt zurückgegeben, | ||
| ==== Fake ==== | ==== Fake ==== | ||
| Ein '' | Ein '' | ||
| - | Oft ersetzen Fakes in Tests Services wie Datenbanken mit einer einfacheren In-Memory-DB. | + | <code javascript> |
| - | <code javascript></ | + | class FakeUserRepository { |
| + | constructor() { | ||
| + | this.users = new Map() | ||
| + | } | ||
| + | |||
| + | save(user) { | ||
| + | this.users.set(user.id, | ||
| + | } | ||
| + | |||
| + | findUserById(id) { | ||
| + | return this.users.get(id) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | const repo = new FakeUserRepository() | ||
| + | repo.save({ id: 1, name: " | ||
| + | |||
| + | const service = new UserService(repo) | ||
| + | |||
| + | expect(service.getUser(1).name).toBe(" | ||
| + | </ | ||
| + | Wie auch in diesem Beispiel, | ||
| ==== Spy ==== | ==== Spy ==== | ||
| Ein '' | Ein '' | ||
| - | <code javascript></ | + | |
| + | Es ist auch möglich, dass der Spy die echte Logik zusätzlich aufruft. | ||
| + | <code javascript> | ||
| + | class EmailServiceSpy { | ||
| + | constructor() { | ||
| + | this.callCount = 0 | ||
| + | this.messages = [] | ||
| + | } | ||
| + | |||
| + | sendEmail(message) { | ||
| + | this.callCount++ | ||
| + | this.messages.push(message) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class UserService { | ||
| + | constructor(emailService) { | ||
| + | this.emailService = emailService | ||
| + | } | ||
| + | |||
| + | registerUser(email) { | ||
| + | this.emailService.sendEmail(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | const emailSpy = new EmailServiceSpy() | ||
| + | const service = new UserService(emailSpy) | ||
| + | |||
| + | service.registerUser(" | ||
| + | |||
| + | if (emailSpy.callCount !== 1) { | ||
| + | throw new Error(" | ||
| + | } | ||
| + | |||
| + | if (emailSpy.messages[0] !== " | ||
| + | throw new Error(" | ||
| + | } | ||
| + | </ | ||
| ==== Mock ==== | ==== Mock ==== | ||
| Ein '' | Ein '' | ||
| - | <code javascript></ | + | <code javascript> |
| + | class OrderService { | ||
| + | constructor(paymentGateway, | ||
| + | this.paymentGateway = paymentGateway | ||
| + | this.repository = repository | ||
| + | } | ||
| + | |||
| + | placeOrder(order) { | ||
| + | this.paymentGateway.authorize(order.amount) | ||
| + | |||
| + | this.repository.save(order) | ||
| + | |||
| + | this.paymentGateway.capture(order.amount) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class PaymentGatewayMock { | ||
| + | constructor() { | ||
| + | this.authorized = false | ||
| + | } | ||
| + | |||
| + | authorize(amount) { | ||
| + | if (this.authorized) { | ||
| + | throw new Error(" | ||
| + | } | ||
| + | this.authorized = true | ||
| + | } | ||
| + | |||
| + | capture(amount) { | ||
| + | if (!this.authorized) { | ||
| + | throw new Error(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | const paymentMock = new PaymentGatewayMock() | ||
| + | |||
| + | const repositoryStub = { | ||
| + | save() {} | ||
| + | } | ||
| + | |||
| + | const service = new OrderService(paymentMock, | ||
| + | |||
| + | service.placeOrder({ amount: 100 }) | ||
| + | </ | ||