6.4. Putting it all together: credit card charging in two steps

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:

  1. Checks the credit card of the customer. If the card is invalid or doesn’t have enough funds, the method stops there.
  2. If the credit card is OK, the price for the products is reserved from the credit card. (This is called an authorization event in credit card terminology.)
  3. The inventory is checked. If the products are in stock and can be shipped, the amount from the card that was previously reserved is now transferred to the account of the e-shop. (This is called a capturing event in credit card terminology.)

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.

Figure 6.4. Business requirements for credit card charging

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.

Listing 6.25. Using mocks and stubs in the same test

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.

Figure 6.5. Two steps of charging a credit card with the same token

The respective unit test is shown next.

Listing 6.26. Verifying a sequence of events with interconnected method calls

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.

Mocks and stubs are relevant only to the scenario being tested

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:

11

A possible solution can be found in the source code of the book at GitHub.

  • The card becomes invalid between the authorize and capture steps.
  • The authorize step succeeds, but the inventory doesn’t have the products in stock.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.166.31