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 16:26] – 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. | ||
| - | ==== Übersicht ==== | + | ^ Double-Typ |
| - | ^ Name ^ Beschreibung ^ Beispiel | + | | Dummy | Platzhalter |
| - | | Dummy | ... | ... | | + | | Stub | Vordefinierte Antworten |
| - | | Mock | ... | ... | | + | | Fake | Vereinfachte echte Implementierung |
| - | | Fake | ... | ... | | + | | Spy | Aufrufe beobachten |
| - | | Spy | ... | ... | | + | | Mock | Überprüfung direkt bei Aufruf |
| - | | Stub | ... | ... | | + | |
| - | | Fake | ... | ... | | + | |
| ==== Dummy ==== | ==== Dummy ==== | ||
| Zeile 16: | Zeile 15: | ||
| Ein '' | Ein '' | ||
| - | <code javascript> | + | <code javascript> |
| + | class DummyLogger { | ||
| + | log() { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | const logger = new DummyLogger() | ||
| + | createUserService(logger) | ||
| + | </ | ||
| + | Im Beispiel ist ersichtlich, | ||
| + | |||
| + | ==== Stub ==== | ||
| + | Ein '' | ||
| + | |||
| + | Dadurch ist ein '' | ||
| + | |||
| + | <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 ==== | ||
| + | Ein '' | ||
| + | |||
| + | <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, ersetzen Fakes oft in Tests Services wie Datenbanken mit einer einfacheren In-Memory-DB. Die Objekte sind dadurch nur zur Laufzeit vorhanden, was aber für die Ausführung des Tests vollkommen ausreicht. | ||
| + | |||
| + | ==== Spy ==== | ||
| + | Ein '' | ||
| + | |||
| + | 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 ==== | ||
| + | Ein '' | ||
| + | <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 }) | ||
| + | </ | ||