Gutscheincodes: von der Anfrage bis zur Freigabe
Kurz gesagt: Eine Anfrage, „ich will Gutscheincodes für den Herbst“, geht durch alles im Kurs. Die Fragen finden den Bedarf und die Menschen, die niemand fragt. Die Story wird nach ihren Regeln aufgeteilt, die Gültigkeitsdauer geht durch Example Mapping. Die Regeln des Codes werden zu Szenarien gegen ein System mit Fehlern, und weil die Änderung den Warenkorbwert berührt, wird auch die Lieferung vor Regression geschützt. Der gefangene Fehler wird zu einem Bericht, zwei Szenarien werden zu Code, und die Matrix sagt, was berührt wird, wenn sich die Anforderung ändert.
Problem
Die Anfrage
Der Inhaber des Shops schreibt an einem Montagmorgen:
„Ich will Gutscheincodes für den Herbst. 10 % Rabatt, bis Ende November. In zwei Wochen ist Freigabe.“
Drei Sätze. Sie enthalten mindestens fünf Regeln, die noch niemand ausgesprochen hat, ein offenes Thema mit Geld darin und einen Menschen, der von der Änderung erst erfährt, wenn er seine Arbeit nicht machen kann. In diesem Projekt gehst du den ganzen Weg: von den drei Sätzen zur freigegebenen und geprüften Änderung.
Die Idee
Der Weg
Jeder Schritt kommt aus einem Modul des Kurses:
- die Fragen: der Bedarf hinter der Anfrage und die Menschen, die gefragt werden müssen;
- die Story und das Aufteilen: Die Anfrage ist groß; sie wird nach ihren Regeln zerschnitten;
- Example Mapping: die Regeln, die Beispiele und die Fragen zur Gültigkeitsdauer des Codes;
- die Szenarien und die Tests: Die Regeln des Codes werden zu Szenarien; die Änderung berührt auch den Warenkorbwert, und die Lieferung hängt davon ab, also wird sie vor Regression geschützt;
- der Bericht: der Fehler, den die Änderung gebracht hat, so beschrieben, dass er beim ersten Mal behoben wird;
- die Automatisierung: Zwei Szenarien für den Gutscheincode werden zu Code in den vier Sprachen;
- die Matrix und die Änderung: was die Tests abdecken und was berührt wird, wenn sich die Anforderung ändert.
Genauer, für Neugierige
Im Browser laufen die Szenarien gegen ein System mit Fehlern. Für den Gutscheincode kennt es drei der Regeln: 10 %, reduzierte Produkte und welcher Rabatt beim Stammkundenstatus gilt. Die Gültigkeitsdauer und „Der Code wurde schon benutzt“ stehen nicht darin: Sie stehen in der Karte, in der Matrix und in der Automatisierung, wo die Szenarien mit den echten Werkzeugen laufen. Die Regression, die Tabelle und der Bericht gehören zur Lieferung: Die Änderung am Code verändert den Warenkorbwert, von dem die Lieferung abhängt, und die Lieferung muss richtig bleiben.
Probier es aus
Die Fragen
Die Idee
Die Antworten
Nach den Gesprächen mit dem Inhaber, dem Marketing und der Buchhaltung sieht die Anfrage so aus:
- der Bedarf: mehr neue Kunden im Herbst. Maß: Erstbestellungen neuer Kunden pro Monat, verglichen mit dem letzten Herbst; gemessen Ende November;
- die Regeln: Der Code gibt 10 % Rabatt; er gilt nicht für reduzierte Produkte; er wird in einer bezahlten Bestellung benutzt („Der Code wurde schon benutzt“); er gilt bis einschließlich zu seinem letzten Tag („Der Code ist abgelaufen“); er addiert sich nicht mit dem Stammkundenstatus, der größere gilt;
- die Buchhaltung: will sehen, welcher Code jeden Rabatt gegeben hat;
- offene Frage: Wird die Schwelle von 50 € für kostenlose Lieferung vor dem Rabatt gezählt oder danach? Der Inhaber entscheidet; bis dahin entscheidet niemand sonst.
Fünf Regeln in einer Story sind viel. Der nächste Schritt ist das Aufteilen.
Übung
Die Story und die Karte
1. Das Aufteilen. Die Story mit allen Regeln des Codes ist für eine Iteration zu groß.
Wähle das Muster, nach dem die Story zerschnitten wird, und baue dann das Aufteilen in der Reihenfolge, in der es gemacht wird.
Als Kunde möchte ich einen Gutscheincode eingeben und einen Rabatt bekommen, damit ich günstiger kaufe.
Schritt 2: Welche Stücke und in welcher Reihenfolge?
Füge die Stücke hinzu, die die Aufteilung bilden, und ordne sie: Das erste wird zuerst gemacht.
Die Stücke
Die Aufteilung
Muster
- Nach Geschäftsregeln: Der Rabatt ist einer, aber es gibt fünf Regeln: 10 %, nicht auf reduzierte Produkte, eine bezahlte Bestellung, eine Gültigkeitsdauer und welcher Rabatt beim Stammkundenstatus gilt. Jede Regel lässt sich einzeln bauen, zeigen und prüfen.
Die Musteraufteilung
- Der Code gibt 10 % Rabatt auf Produkte zum vollen Preis
- Reduzierte Produkte bekommen keinen Rabatt durch den Gutscheincode
- Der Code kann in einer bezahlten Bestellung benutzt werden; danach „Der Code wurde schon benutzt“
- Der Code gilt bis zu seinem letzten Tag; danach „Der Code ist abgelaufen“
- Ein Stammkunde mit Code: Der größere Rabatt gilt
Jede Regel ist eine Story, die sich einzeln zeigen lässt. 10 % ist die Basis und kommt zuerst. „Der größere gilt“ ergibt erst mit zwei Rabatten Sinn, also kommt es zuletzt. Das Feld im Warenkorb und die Tabelle in der Datenbank sind Schichten: Niemand kann nur sie ausprobieren.
2. Die Gültigkeitsdauer. Das erste Stück nach 10 % ist die Gültigkeitsdauer. Die Three Amigos haben sich mit den Karten hingesetzt.
Lege jede Karte an ihren Platz und entscheide dann, was die Story ist.
Als Kunde möchte ich wissen, bis wann der Code gilt, damit ich ihn rechtzeitig benutze.
Klicke bei jeder Karte auf „Legen als…“ und wähle: Regel (wird zur Spalte), Beispiel zu einer Regel oder Frage. Die Pfeiltasten wechseln zwischen den Möglichkeiten, Esc schließt. Mit der Maus geht es auch: Zieh die Karte an ihren Platz.
Regeln
Noch keine Regeln. Lege eine Karte als Regel, und sie wird zur Spalte.
Fragen
- Noch keine Fragen.
Nicht gelegte Karten
Ein abgelaufener Code wird mit „Der Code ist abgelaufen“ abgelehnt, und der Warenkorbwert bleibt ohne Rabatt
Eine Bestellung am 30. November mit HERBST10: Ein T-Shirt für 20,00 € kostet 18,00 €
Der Code wurde am 30. November um 23:50 eingegeben, und die Bestellung wurde am 1. Dezember um 00:10 bezahlt. Gilt er?
Der letzte Tag endet um Mitternacht nach wessen Uhr: der des Shops oder der des Kunden?
Der Code gilt bis einschließlich zu seinem letzten Tag
Eine Bestellung am 1. Dezember mit HERBST10: „Der Code ist abgelaufen“, das T-Shirt kostet weiter 20,00 €
HERBST10 gilt bis zum 30. November. Eine Bestellung am 15. November: Ein T-Shirt für 20,00 € kostet 18,00 €
Das geordnete Board
- Der Code gilt bis einschließlich zu seinem letzten Tag
- HERBST10 gilt bis zum 30. November. Eine Bestellung am 15. November: Ein T-Shirt für 20,00 € kostet 18,00 €
- Eine Bestellung am 30. November mit HERBST10: Ein T-Shirt für 20,00 € kostet 18,00 €
- Ein abgelaufener Code wird mit „Der Code ist abgelaufen“ abgelehnt, und der Warenkorbwert bleibt ohne Rabatt
- Eine Bestellung am 1. Dezember mit HERBST10: „Der Code ist abgelaufen“, das T-Shirt kostet weiter 20,00 €
Fragen
- Der letzte Tag endet um Mitternacht nach wessen Uhr: der des Shops oder der des Kunden?
- Der Code wurde am 30. November um 23:50 eingegeben, und die Bestellung wurde am 1. Dezember um 00:10 bezahlt. Gilt er?
Was ist die Story? Bereit für die Arbeit. Beide Fragen gehen um denselben Moment, Mitternacht am letzten Tag, und der Inhaber klärt sie in einem Satz. Die Regeln und die Beispiele sind klar, die Arbeit kann beginnen, und die Antwort wird ein weiteres Beispiel.
Beide Fragen gehen um Mitternacht am letzten Tag. Sie wirken klein, aber die Antwort entscheidet, welcher Kunde um 00:10 „Der Code ist abgelaufen“ sieht. Du triffst sie in der Automatisierung wieder.
Übung
Die Szenarien für den Code
Drei der Regeln aus dem Aufteilen laufen gleich hier: 10 %, reduzierte Produkte und der Stammkunde mit Code. Ein Szenario pro Beispiel, in der Sprache des Inhabers.
Schreibe die Szenarien für den Gutscheincode so, dass alle sechs Fehler rund um die Rabatte gefangen werden.
Lösung
# language: de
Funktionalität: Gutscheincode
Szenario: Der Code gibt 10 % auf ein Produkt zum vollen Preis
Angenommen ein gültiger Gutscheincode
Und ein Produkt zum vollen Preis
Und ein Kunde ohne Stammkundenstatus
Wenn der Kunde bezahlt
Dann beträgt der Rabatt 10 %
Szenario: Der Code gilt nicht für ein reduziertes Produkt
Angenommen ein gültiger Gutscheincode
Und ein reduziertes Produkt
Und ein Kunde ohne Stammkundenstatus
Wenn der Kunde bezahlt
Dann gibt es keinen Rabatt
Szenario: Ein Stammkunde mit Code bekommt den größeren Rabatt
Angenommen ein Stammkunde
Und ein gültiger Gutscheincode
Und ein Produkt zum vollen Preis
Wenn der Kunde bezahlt
Dann beträgt der Rabatt 10 %
Szenario: Ein Stammkunde mit Code für ein reduziertes Produkt behält den Stammkundenrabatt
Angenommen ein Stammkunde
Und ein gültiger Gutscheincode
Und ein reduziertes Produkt
Wenn der Kunde bezahlt
Dann beträgt der Rabatt 5 %
Szenario: Ein Stammkunde ohne Code
Angenommen ein Stammkunde
Und eine Bestellung ohne Gutscheincode
Und ein Produkt zum vollen Preis
Wenn der Kunde bezahlt
Dann beträgt der Rabatt 5 %
Die kniffligsten Fehler gehören zum Stammkunden: ob sich die Rabatte addieren, welcher gewinnt und was mit dem Stammkundenrabatt geschieht, wenn der Code für das Produkt nicht gilt. Und ein Stammkunde ohne Code ist auch ein Beispiel.
Die Idee
Die Änderung berührt die Lieferung
Der Gutscheincode verändert den Warenkorbwert. Die Lieferung hängt vom Warenkorbwert ab: kostenlos ab 50,00 € einschließlich, sonst 4,90 €. Der Programmierer des Codes wird genau die Berechnung des Warenkorbwerts anfassen.
Was auch immer der Inhaber zur Schwelle vor oder nach dem Rabatt entscheidet, die Lieferregel aus dem Warenkorbwert muss richtig bleiben. Deshalb wird die Lieferung vor der Änderung vor Regression geschützt: Szenarien für die vereinbarten Beispiele und Tests für die technischen Fälle, die fehlschlagen, wenn rund um die Grenze etwas kaputtgeht.
Übung
Die Regression der Lieferung
1. Die Szenarien. Wenige Szenarien, eines für jedes vereinbarte Beispiel.
Schreibe die Lieferszenarien so, dass sie die fünf Fehler rund um die Grenze und den leeren Warenkorb fangen.
Lösung
# language: de
Funktionalität: Kostenlose Lieferung
Szenario: Eine Bestellung genau an der Grenze
Angenommen ein Warenkorb von 50,00 €
Wenn ich bestelle
Dann ist die Lieferung kostenlos
Szenario: Eine Bestellung knapp unter der Grenze
Angenommen ein Warenkorb von 49,99 €
Wenn ich bestelle
Dann beträgt die Lieferung 4,90 €
Szenario: Ein leerer Warenkorb
Angenommen ein leerer Warenkorb
Wenn ich bestelle
Dann wird die Bestellung abgelehnt
Die drei Beispiele sind die aus dem Example Mapping zur Lieferung: genau 50,00 €, 49,99 € und ein leerer Warenkorb. 49,00 € liegt unter der Grenze, aber weit davon entfernt: Wird der Warenkorbwert auf ganze Euro gerundet, sind 49,00 € immer noch 49, und der Fehler kommt durch.
2. Die technischen Fälle. Die Tabelle ist für den Test auf Komponentenebene: die Fälle, die das Geschäft nicht lesen will.
Schreibe die Fälle, die alle sechs Fehler fangen, einschließlich des Überbleibsels des alten Tarifs für große Bestellungen.
Die Regel: Die Lieferung ist ab einer Bestellung von 50 € (einschließlich) kostenlos, sonst kostet sie 4,90 €. Ein leerer Warenkorb kann nicht bestellt werden.
| Eingabe | Erwartet | Das richtige System | |||
|---|---|---|---|---|---|
| # | Warenkorbwert | Abgelehnt | Lieferung | ||
Eine leere Ergebniszelle wird nicht geprüft. Beträge schreibt man wie 49,99.
Lösung
| Warenkorbwert | Abgelehnt | Lieferung |
|---|---|---|
| 0 | ja | |
| 49,99 | nein | 4,90 |
| 50 | nein | 0 |
| 150 | nein | 0 |
Die große Bestellung (150 €) steht nicht in den Szenarien, weil das Geschäft sie nicht als Beispiel vereinbart hat. Aber das Überbleibsel des alten Tarifs („ab 100 € wieder 4,90 €“) zeigt sich erst über 100 €.
Übung
Der gefangene Fehler
1. Der Bericht. Der Programmierer des Gutscheincodes berechnet den Warenkorbwert mit Bruchzahlen und rundet ihn auf ganze Euro. Das Szenario für 49,99 € schlägt fehl.
Finde einen Warenkorbwert, bei dem sich der Fehler zeigt, und schreibe den Bericht.
bei Beträgen mit Cent knapp unter 50 €
Die Regel: Die Lieferung ist ab einer Bestellung von 50 € (einschließlich) kostenlos, sonst kostet sie 4,90 €. Ein leerer Warenkorb kann nicht bestellt werden.
Schritte zum Reproduzieren
- Noch keine Schritte. Füge sie aus dem Vokabular unten hinzu.
Die Schritte stammen aus dem Vokabular der Funktionalität, wie in den Szenarien. Die Werte stehen im Schritt selbst: den Betrag wie 50,00.
Der Musterbericht
- Titel
- Die Lieferung ist bei einer Bestellung von 49,50 € kostenlos
- Schritte zum Reproduzieren
- Angenommen ein Warenkorb von 49,50 €
- Wenn ich bestelle
- Erwartet
- die Lieferung beträgt 4,90 €
- Tatsächlich
- die Lieferung ist kostenlos
- Schweregrad
- mittel. Der Shop verliert 4,90 € nur bei Bestellungen zwischen 49,50 € und 49,99 €. Der Bereich ist schmal, aber der Fehler ist echt, und die Kunden, die ihn finden, werden ihn ausnutzen.
- Priorität
- hoch. Der Fehler kam mit der Änderung am Gutscheincode, die mit der Kampagne live geht. Die Korrektur ist klein und muss in dieselbe Freigabe; sonst verbreitet die Kampagne ihn.
Der Fehler zeigt sich zwischen 49,50 € und 49,99 €: Dort ergibt die Rundung 50 €. Bei 49,00 € berechnen beide Systeme 4,90 €, also reproduziert ein solcher Bericht nichts. Die Priorität ist hoch, weil der Fehler mit der Kampagne rausgeht.
Die Idee
Zwei Szenarien automatisieren
Die zwei Szenarien zum Gutscheincode, die der Inhaber gelesen und abgenommen hat:
# language: deFunktionalität: Gutscheincode Der Gutscheincode gibt 10 % Rabatt bis einschließlich zu seinem letzten Tag.
Szenario: Der Code gibt 10 % Angenommen ein Warenkorb von 20,00 € Wenn ich den Code HERBST10 anwende Dann beträgt die Summe 18,00 €
Szenario: Abgelaufener Code Angenommen ein Warenkorb von 20,00 € Und der Code HERBST10 ist abgelaufen Wenn ich den Code HERBST10 anwende Dann sehe ich, dass der Code abgelaufen ist Dann beträgt die Summe 20,00 €Die Klasse, die den Code anwendet. Der Warenkorbwert ist in Cent, und der Tag ist eine Eingabe, nicht „heute“: Das ist die Antwort auf die Frage nach Mitternacht aus der Karte und auf die Lektion über Tests in der CI:
package shop;
import java.time.LocalDate;
public class PromoCode { private final String code; private final LocalDate lastDay;
public PromoCode(String code, LocalDate lastDay) { this.code = code; this.lastDay = lastDay; }
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. public int apply(int total, LocalDate day) { if (day.isAfter(lastDay)) { throw new IllegalArgumentException("Der Code ist abgelaufen"); } return total - total / 10; }}namespace Shop;
public class PromoCode(string code, DateOnly lastDay){ public string Code => code;
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. public int Apply(int total, DateOnly day) { if (day > lastDay) { throw new ArgumentException("Der Code ist abgelaufen"); } return total - total / 10; }}class PromoCode: def __init__(self, code, last_day): self.code = code self.last_day = last_day
def apply(self, total, day): """10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt.""" if day > self.last_day: raise ValueError("Der Code ist abgelaufen") return total - total // 10export class PromoCode { constructor(code, lastDay) { this.code = code; this.lastDay = lastDay; }
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. apply(total, day) { if (day > this.lastDay) { throw new Error("Der Code ist abgelaufen"); } return total - Math.floor(total / 10); }}Der Schritt „Wenn“ wendet den Code an, und der Schritt „Dann“ prüft die Meldung:
@When("ich den Code {word} anwende")public void apply(String code) { try { total = new PromoCode(code, LAST_DAY).apply(total, today); } catch (IllegalArgumentException e) { refusal = e.getMessage(); }}[When("ich den Code {word} anwende")]public void Apply(string code){ try { total = new PromoCode(code, LastDay).Apply(total, today); } catch (ArgumentException e) { refusal = e.Message; }}@when("ich den Code {code} anwende")def step_apply(context, code): try: context.total = PromoCode(code, LAST_DAY).apply(context.total, context.today) except ValueError as e: context.refusal = str(e)When("ich den Code {word} anwende", function (code) { try { this.total = new PromoCode(code, LAST_DAY).apply(this.total, this.today); } catch (e) { this.refusal = e.message; }});@Then("sehe ich, dass der Code abgelaufen ist")public void toldExpired() { assertEquals("Der Code ist abgelaufen", refusal);}[Then("sehe ich, dass der Code abgelaufen ist")]public void ToldExpired() => Assert.Equal("Der Code ist abgelaufen", refusal);@then("sehe ich, dass der Code abgelaufen ist")def step_told_expired(context): assert context.refusal == "Der Code ist abgelaufen", f"Meldung: {context.refusal}"Then("sehe ich, dass der Code abgelaufen ist", function () { assert.equal(this.refusal, "Der Code ist abgelaufen");});Die ganze Datei mit den Schritten, mit dem echten Werkzeug ausgeführt. Beide Szenarien bestehen:
package shop;
import io.cucumber.java.ParameterType;import io.cucumber.java.en.Given;import io.cucumber.java.en.Then;import io.cucumber.java.en.When;
import java.time.LocalDate;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class PromoSteps { // Der letzte Tag des Codes in den Szenarien. private static final LocalDate LAST_DAY = LocalDate.of(2026, 11, 30);
private int total; private LocalDate today = LocalDate.of(2026, 11, 15); private String refusal;
@ParameterType(name = "Betrag", value = "\\d+,\\d{2}") public int amount(String text) { return Integer.parseInt(text.replace(",", "")); }
@Given("ein Warenkorb von {Betrag} €") public void cart(int cents) { total = cents; }
@Given("der Code {word} ist abgelaufen") public void expired(String code) { today = LAST_DAY.plusDays(1); }
@When("ich den Code {word} anwende") public void apply(String code) { try { total = new PromoCode(code, LAST_DAY).apply(total, today); } catch (IllegalArgumentException e) { refusal = e.getMessage(); } }
@Then("beträgt die Summe {Betrag} €") public void totalIs(int cents) { assertEquals(cents, total); }
@Then("sehe ich, dass der Code abgelaufen ist") public void toldExpired() { assertEquals("Der Code ist abgelaufen", refusal); }}OK Abgelaufener CodeOK Der Code gibt 10 %Szenarien: 2, bestanden: 2, fehlgeschlagen: 0using Reqnroll;using Xunit;
namespace Shop;
[Binding]public class PromoSteps{ // Der letzte Tag des Codes in den Szenarien. private static readonly DateOnly LastDay = new(2026, 11, 30);
private int total; private DateOnly today = new(2026, 11, 15); private string refusal;
[StepArgumentTransformation(@"(\d+,\d{2})", Name = "Betrag")] public int Amount(string text) => int.Parse(text.Replace(",", ""));
[Given("ein Warenkorb von {Betrag} €")] public void Cart(int cents) => total = cents;
[Given("der Code {word} ist abgelaufen")] public void Expired(string code) => today = LastDay.AddDays(1);
[When("ich den Code {word} anwende")] public void Apply(string code) { try { total = new PromoCode(code, LastDay).Apply(total, today); } catch (ArgumentException e) { refusal = e.Message; } }
[Then("beträgt die Summe {Betrag} €")] public void TotalIs(int cents) => Assert.Equal(cents, total);
[Then("sehe ich, dass der Code abgelaufen ist")] public void ToldExpired() => Assert.Equal("Der Code ist abgelaufen", refusal);}OK Abgelaufener CodeOK Der Code gibt 10 %Szenarien: 2, bestanden: 2, fehlgeschlagen: 0from datetime import date, timedelta
from behave import given, register_type, then, when
from promo_code import PromoCode
# Der letzte Tag des Codes in den Szenarien.LAST_DAY = date(2026, 11, 30)
def parse_amount(text): return int(text.replace(",", ""))
parse_amount.pattern = r"\d+,\d{2}"register_type(Amount=parse_amount)
@given("ein Warenkorb von {total:Amount} €")def step_cart(context, total): context.total = total
@given("der Code {code} ist abgelaufen")def step_expired(context, code): context.today = LAST_DAY + timedelta(days=1)
@when("ich den Code {code} anwende")def step_apply(context, code): try: context.total = PromoCode(code, LAST_DAY).apply(context.total, context.today) except ValueError as e: context.refusal = str(e)
@then("beträgt die Summe {total:Amount} €")def step_total(context, total): assert context.total == total, f"Summe ist {context.total}, erwartet {total}"
@then("sehe ich, dass der Code abgelaufen ist")def step_told_expired(context): assert context.refusal == "Der Code ist abgelaufen", f"Meldung: {context.refusal}"OK Abgelaufener CodeOK Der Code gibt 10 %Szenarien: 2, bestanden: 2, fehlgeschlagen: 0import { Given, When, Then, defineParameterType } from "@cucumber/cucumber";import assert from "node:assert/strict";import { PromoCode } from "../../promo-code.js";
// Der letzte Tag des Codes in den Szenarien.const LAST_DAY = "2026-11-30";
defineParameterType({ name: "Betrag", regexp: /\d+,\d{2}/, transformer: (text) => Number(text.replace(",", "")),});
Given("ein Warenkorb von {Betrag} €", function (cents) { this.total = cents;});
Given("der Code {word} ist abgelaufen", function (code) { this.today = "2026-12-01";});
When("ich den Code {word} anwende", function (code) { try { this.total = new PromoCode(code, LAST_DAY).apply(this.total, this.today); } catch (e) { this.refusal = e.message; }});
Then("beträgt die Summe {Betrag} €", function (cents) { assert.equal(this.total, cents);});
Then("sehe ich, dass der Code abgelaufen ist", function () { assert.equal(this.refusal, "Der Code ist abgelaufen");});OK Abgelaufener CodeOK Der Code gibt 10 %Szenarien: 2, bestanden: 2, fehlgeschlagen: 0Und wenn der Programmierer die Gültigkeitsdauer vergisst, gibt der abgelaufene Code immer noch 10 % Rabatt, und das Szenario „Abgelaufener Code“ schlägt fehl:
package shop;
import java.time.LocalDate;
public class PromoCode { private final String code; private final LocalDate lastDay;
public PromoCode(String code, LocalDate lastDay) { this.code = code; this.lastDay = lastDay; }
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. public int apply(int total, LocalDate day) { return total - total / 10; }}FEHLER Abgelaufener Code: expected: <Der Code ist abgelaufen> but was: <null>OK Der Code gibt 10 %Szenarien: 2, bestanden: 1, fehlgeschlagen: 1namespace Shop;
public class PromoCode(string code, DateOnly lastDay){ public string Code => code;
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. public int Apply(int total, DateOnly day) { return total - total / 10; }}FEHLER Abgelaufener Code: Assert.Equal() Failure: Strings differ Expected: "Der Code ist abgelaufen" Actual: nullOK Der Code gibt 10 %Szenarien: 2, bestanden: 1, fehlgeschlagen: 1class PromoCode: def __init__(self, code, last_day): self.code = code self.last_day = last_day
def apply(self, total, day): """10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt.""" return total - total // 10FEHLER Abgelaufener Code: ASSERT FAILED: Meldung: NoneOK Der Code gibt 10 %Szenarien: 2, bestanden: 1, fehlgeschlagen: 1export class PromoCode { constructor(code, lastDay) { this.code = code; this.lastDay = lastDay; }
// 10 % von der Summe in Cent. Ein abgelaufener Code wird abgelehnt. apply(total, day) { return total - Math.floor(total / 10); }}FEHLER Abgelaufener Code: null !== 'Der Code ist abgelaufen'OK Der Code gibt 10 %Szenarien: 2, bestanden: 1, fehlgeschlagen: 1Genauer, für Neugierige
Diese Szenarien stehen nicht im Vokabular des Motors des Kurses, also werden sie im Browser nicht gegen ein System mit einem Fehler geprüft. Sie laufen mit Cucumber-JVM, Reqnroll, behave und cucumber-js, wie im Modul „Automatisierung“, und ihre Ausgabe wird verifiziert. Der Rabatt wird auf einen ganzen Cent abgerundet (total / 10 bei ganzen Zahlen); bei Beträgen wie 20,00 € macht das keinen Unterschied, aber es ist eine Entscheidung, die die Buchhaltung bestätigen muss.
Übung
Die Matrix und die Änderung
1. Überdeckung und Auswirkung. Der Herbst ist vorbei. Das Maß hat gezeigt, dass die meisten Codes von Bestandskunden benutzt wurden, und der Inhaber ändert die Regel: Der Code gilt nur für die erste Bestellung des Kunden.
Markiere die Verbindungen. Wähle dann im zweiten Schritt, welche Tests für die Änderung überprüft werden müssen.
Tests
- T-1: Ein neuer Kunde, ein T-Shirt für 20,00 € mit HERBST10: 18,00 €.
- T-2: Ein neuer Kunde, eine reduzierte Jeans für 40,00 € mit HERBST10: 40,00 €.
- T-3: Ein neuer Kunde, ein T-Shirt für 20,00 € und eine reduzierte Jeans für 40,00 € mit HERBST10: 58,00 €.
- T-4: Der Kunde hat schon eine Bestellung mit HERBST10 bezahlt. In einer neuen Bestellung gibt er HERBST10 ein: „Der Code wurde schon benutzt“.
- T-5: Ein neuer Kunde gibt HERBST10 am 1. Dezember ein, nach dem letzten Tag: „Der Code ist abgelaufen“.
- T-6: Ein Stammkunde mit HERBST10, ein T-Shirt für 20,00 €: 18,00 €, nicht 17,00 €.
- T-7: Ein neuer Kunde gibt HERBST10 am 30. November ein, dem letzten Tag: Ein T-Shirt für 20,00 € kostet 18,00 €.
Klicke auf die Zelle, in der der Test die Anforderung prüft; noch einmal, um die Verbindung zu entfernen. Die Pfeiltasten wechseln zwischen den Zellen, Leertaste oder Enter markiert.
| Anforderungen | T-1: Ein neuer Kunde, ein T-Shirt für 20,00 € mit HERBST10: 18,00 €. | T-2: Ein neuer Kunde, eine reduzierte Jeans für 40,00 € mit HERBST10: 40,00 €. | T-3: Ein neuer Kunde, ein T-Shirt für 20,00 € und eine reduzierte Jeans für 40,00 € mit HERBST10: 58,00 €. | T-4: Der Kunde hat schon eine Bestellung mit HERBST10 bezahlt. In einer neuen Bestellung gibt er HERBST10 ein: „Der Code wurde schon benutzt“. | T-5: Ein neuer Kunde gibt HERBST10 am 1. Dezember ein, nach dem letzten Tag: „Der Code ist abgelaufen“. | T-6: Ein Stammkunde mit HERBST10, ein T-Shirt für 20,00 €: 18,00 €, nicht 17,00 €. | T-7: Ein neuer Kunde gibt HERBST10 am 30. November ein, dem letzten Tag: Ein T-Shirt für 20,00 € kostet 18,00 €. | Abgedeckt durch |
|---|---|---|---|---|---|---|---|---|
| R-1 Ein Gutscheincode gibt 10 % Rabatt. | 0 | |||||||
| R-2 Ein Gutscheincode gilt nicht für reduzierte Produkte. | 0 | |||||||
| R-3 Ein Code kann in einer bezahlten Bestellung benutzt werden. Ein zweiter Versuch: „Der Code wurde schon benutzt“. | 0 | |||||||
| R-4 Ein Code gilt bis einschließlich zu seinem letzten Tag. Danach: „Der Code ist abgelaufen“. | 0 | |||||||
| R-5 Rabatte addieren sich nicht: Der größere gilt. | 0 | |||||||
| R-6 Die Bestellung zeigt, welcher Code den Rabatt gegeben hat. | 0 | |||||||
| Prüft | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Die Referenzmatrix
- R-1: T-1, T-3
- R-2: T-2, T-3
- R-3: T-4
- R-4: T-5, T-7
- R-5: T-6
- R-6: nicht abgedeckt
Welche Tests müssen überprüft werden? T-4, T-6. „T-4“ muss überprüft werden: Der Kunde hat schon eine Bestellung, der Code wird weiter abgelehnt, aber mit welcher Meldung, muss entschieden werden. „T-6“ ist nicht mit „R-3“ verbunden, aber ein Stammkunde hat frühere Bestellungen: Der Code gilt für ihn nicht mehr, und das T-Shirt kostet durch den Stammkundenstatus 19,00 €. „T-1“, „T-2“, „T-3“, „T-5“ und „T-7“ gelten für einen neuen Kunden und bleiben. Ein neuer Test wird auch gebraucht: Ein Kunde mit einer früheren Bestellung ohne Code gibt HERBST10 ein, und der Code wird abgelehnt.
„R-6“ kam aus dem Abnahmetest (Buchhaltung) und hat noch keinen Test. Für die Änderung ist „T-4“ mit der Anforderung verbunden, „T-6“ aber nicht: Der Stammkunde hat jedoch frühere Bestellungen, und der Code gilt für ihn nicht mehr. Die Verbindungen in der Matrix sind der Anfang der Analyse, nicht ihr Ende.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Komponententests · Tests in der CI · Abnahmetest mit dem Geschäft · Messen nach der Freigabe
- Aufgaben zum Thema: Projekt: Promo-Codes