All the examples shown so far illustrate various features of mocks and stubs. I’ll close this chapter with a bigger example that combines most of the techniques shown so far and is closer to what you’d write in a production application.
The fullCheckout()method does the following:
In listing 6.14, you can see these two methods (for authorization and capturing) in the credit card processor class. Figure 6.4 is a diagram of what you want to test.
As a starting point, the first scenario that you’ll test is the case where the card doesn’t have enough money. The Spock test is shown in the next listing.
The resulting code doesn’t have any surprises. Because you directly mock the credit card processor to assume that the card doesn’t have enough money, the charging process stops.
Things get more interesting if you want to write a unit test for the full scenario, where the card has money. The complicated part here is the two-step process between the authorize and capture steps. The reason for this is that the response from the first is a special token (assume that in this example it’s a single string). Then when the basket calls the capture step, it must pass the same token to the credit card processor. This way, the credit card processor can link the two events together and distinguish multiple capture events.
To further complicate things, assume also that the credit card processor wants the current date prepended to the token for logistical reasons. Figure 6.5 shows a sample conversation between the basket class and the credit card processor.
The respective unit test is shown next.
This listing demonstrates several key points. First, this time the warehouse inventory is a mock instead of a stub because you want to verify the correct calling of its methods. You also want to verify that it gets non-null arguments.
Mocks and stubs support the with() Spock method that was introduced in chapter 4. You’ve used it to group the two interactions of the warehouse inventory.
To verify that the basket class honors the token given back by the credit card processor, you create your own dummy token (named sample) and pass it to the basket when the authorization step happens. You can then verify that the token handed to the capture event is the same. Because the basket also prepends the token with the date (which is obviously different each time the test runs), you have to use the endsWith() method in the Groovy closure that matches the token.
If you look at listing 6.25, you’ll see that the warehouse is a stub. But in listing 6.26, it’s a mock. It’s therefore possible to create stubs of a specific class in one unit test, and mocks of the same class in another unit test, depending on your business needs. Also, it’s possible to have Spock tests that use only stubs, tests that use only mocks, and tests that use both depending on the case (as you’ll see if you look back at the examples of this chapter). Use whatever you need according to the situation.
And there you have it! You’ve tested two credit card scenarios without charging a real credit card and without calling the real credit card service, which might be slow to initialize. As an exercise,[11] feel free to create more unit tests to cover these scenarios:
A possible solution can be found in the source code of the book at GitHub.
3.142.166.31