what is going on here?
@Test
void verifyGatewayIsCalledExactlyOnceWithCorrectAmount() {
when(mockGateway.charge(123)).thenReturn(true);
service.charge(new Order(123));
// confirm we called charge(123) exactly once, no more, no less
verify(mockGateway, times(1)).charge(123);
verifyNoMoreInteractions(mockGateway);
}
This test is verifying not just the outcome of calling service.charge(...), but how the method interacts with its dependency (PaymentGateway). This is called interaction testing—you're checking that the correct method was called, with the correct data, exactly the right number of times.
Let’s walk through it line by line:
🔧 when(mockGateway.charge(123)).thenReturn(true);
You're stubbing the mock so that if charge(123) is called, it returns true. This ensures the service method doesn’t fail due to an unexpected mock return.
🚀 service.charge(new Order(123));
You're calling the actual method under test. This is where OrderService calls mockGateway.charge(...) internally with the order's amount.
✅ verify(mockGateway, times(1)).charge(123);
This line is the heart of the test: it verifies that the mock's charge(123) method was called exactly once. If it was never called, or called with a different amount, or called more than once—it’ll fail.
🛑 verifyNoMoreInteractions(mockGateway);
This adds an extra safety check: you assert that no other interactions with mockGateway happened besides the charge(123) call. It's like saying: “Only this, and nothing else.”
Why this test is useful
This is a great sanity test to ensure that:
Your OrderService is doing what it should (delegating to the gateway)
You’re using that dependency correctly
No extra or accidental gateway calls sneak in later
This kind of verification is especially important in systems where external calls (e.g. APIs, payments, emails) need to happen precisely once, and not more.
Want to enhance this by verifying inputs with argument matchers, or checking that no calls happen for invalid orders? I’d love to show you!
Top comments (0)