When your shop calls another service, like a payment provider, your tests shouldn't call that service too. The real one may not be running, it charges real money, and you can't make it give the answer you want to test, like a declined card.
patch swaps a static method for a fake called a mock, until the mock is closed. Open it in a try (…) block and it closes when the block ends, which puts the real method back. Whatever you give the mock's thenReturn is what the code gets back when it calls the method. Here a test fakes a shipping service on another route:
ResponseEntity<Map> response;
try (Mock fakeQuote = patch(Shipping.class, "quote")) {
fakeQuote.thenReturn(Map.of("price", 5));
response = client.getForEntity("/cart/shipping", Map.class);
}
assertEquals(5, response.getBody().get("shipping"));
response is declared above the try, so the check below the block can still read it. In this shop, paying an order calls Payments.charge(amount, orderId). When the card is declined, the shop must answer 402 Payment Required, and the order must stay "pending". The check runs your tests on the shop and on two broken copies, then counts the calls that reached the real provider. When you're done, Run prints:
Your tests on the shop:
testDeclinedCard ... ok
testNewOrderIsPending ... ok
2 tests: OK
Your tests on a copy that marks the order paid before it asks the provider:
testDeclinedCard ... FAIL
AssertionError: expected: <pending> but was: <paid>
testNewOrderIsPending ... ok
2 tests: 1 failed, so they caught this bug
Your tests on a copy that ignores what the provider answers:
testDeclinedCard ... FAIL
AssertionError: expected: <402> but was: <201>
testNewOrderIsPending ... ok
2 tests: 1 failed, so they caught this bug
Calls to the real payment provider: 0
Your task: write testDeclinedCard. Patch Payments.charge so it answers Map.of("error", "card_declined"), pay order 1 with POST /orders/1/pay, check that the status code is 402, then check that GET /orders/1 still shows the status "pending".
Assignment
Follow the Coding Tutorial to test a declined card, with a mock in place of the payment provider.
Hint
Declare response above the try block. Call fakeCharge.thenReturn before the POST, and keep the POST inside the block, where Payments.charge is the mock. The checks can go below the block.
Free plan: 30 tutor messages. PRO is unlimited.
