6.3. Mocks: verifying values returned from the class under test

Stubs are great when your class under test already has methods that allow you to understand whether everything works as expected (such as the canShipCompletely() method of the basket class). But most of the time, the only way to understand what happened during the unit test is to have a “log” of what methods were called along with their arguments and their responses.

Mocks are the answer to this need. By mocking a collaborator of the class under test, you not only can preprogram it with canned responses, but also can query it (after the unit test has finished) about all its interactions.

Spock has a huge range of options when it comes to mocks

Spock supports many features when it comes to mocking. Some are more useful than others, some apply only to extreme cases, and some are so confusing that I avoid them on purpose. This chapter shows the features I find useful (I’ve left out about 10% of Spock features). You can always consult the official Spock website as a reference.

6.3.1. All capabilities of stubs exist in mocks as well

The first thing to get out of the way is that mocks are a superset of stubs. All code listings I’ve shown you so far will work even if you use a mock. As an example, here’s listing 6.2 written with a mock this time. Apart from a single line, the rest of the code is exactly the same.

Listing 6.13. Stubbing mocks

In Spock, you use stubs when you want to denote that the fake class you’re going to use will come with only preprogrammed behavior and its interactions won’t be verified. Of the two listings, the semantically correct is 6.2 (with the stub) because the warehouse inventory is never queried at the end of the unit test for its interactions with the basket class.

Spock enforces this convention, so although mocks will work in the place of stubs, the opposite doesn’t apply. Attempting to use a stub in place of a mock will throw an error when Spock runs the unit test.

6.3.2. Simple mocking—examining whether a method was called

Let’s add another collaborator class in the electronic basket example. In the following listing, you’ll add the capability to charge credit cards.

Listing 6.14. Java skeleton for credit card charging

The credit card system is implemented by an external library (imagine that you don’t even have the source code). Reading its API documentation, you see a big warning: its developers explain that the shutdown() method must be called whenever a credit card charge happens.[7]

7

Otherwise, the world will explode.

Your job is to write a unit test that verifies the call of this method by the basket class without charging a credit card. You could get away with a stub if the credit card processor had a method named shutdownWasCalled()! But it doesn’t.

You can use a mock instead of a pure stub, as shown in the following listing.

Listing 6.15. Verification of a mocked method

The important code line of this listing is the last one. Unlike all previous Spock tests, it doesn’t contain a standard assert statement (checked according to Groovy truth). This line is special Spock syntax and comes in this format:

N * mockObject.method(arguments)

When Spock sees this line, it makes the test pass only if that method on the mock has been called N times with the arguments provided (which can also be argument matchers, as with stubs).

The last line in the listing means, “After this test is finished, I expect that the number of times the shutdown() method was called is once.” The test will pass if this sentence is true and will fail in any other case.

Assume that with that unit test in place, a developer introduces a bug in the basket class that calls the shutdown() method two times. Spock will instantly fail the test with the error message shown in figure 6.3.

Figure 6.3. Spock fails the test when the mocked method is called twice.

Spock knows the exact invocations of all mocks because during the test, it has replaced the classes with its own proxies that record everything.

6.3.3. Verifying order of interactions

With the mock for the credit card processor in place, you can ensure that the credit card service is shut down after the transaction (and without charging a real credit card). But listing 6.13 misses the sequence of calls. How do you know that the shutdown() method is called at the end, and not before the credit card charge step (which would be an obvious bug)? Listing 6.13 doesn’t cover this scenario.

Your first impulse, to check the order of calls that happen with the credit card service, would be to write something like this:

then: "credit card is charged and CC service is closed down"
1 * creditCardSevice.sale(1200,customer)
1 * creditCardSevice.shutdown()

This won’t work as expected. Spock doesn’t pay any attention to the order of verifications inside a specific then: block. The preceding unit test will always pass, regardless of the exact sequence of events (if both of them are correct on their own).

The correct unit test needs to exploit the fact that multiple then: blocks are checked in order by Spock,[8] as shown in the following listing.

8

This was also shown in chapter 4.

Listing 6.16. Verification of a specific order of mocked methods

Notice that in this test, you want to focus on the order of events and nothing else, so you’ve used unconditional argument matchers for the arguments of the sale() method because you don’t care about them in this test. (Usually, there should be another unit test focusing on them.)

6.3.4. Verifying number of method calls of the mocked class

If you already have significant experience with other mocking frameworks,[9] you should have noticed something strange in listings 6.15 and 6.16. In listing 6.14, you’re clearly noting to Spock that you expect the sale() method to be called. But listing 6.13 mentions nothing about the sale() method. How does the test in listing 6.13 pass?

9

And have been paying close attention to the code listings.

It turns out that mocks and stubs created by Spock are lenient by default. The test will fail only if the behavior of the mocks is contained in the then: block against your explicit instructions. Calling a method of a mock that was never mentioned has no negative effect. Not calling a stubbed/mocked method also doesn’t affect the unit test.

When you call a mocked method that doesn’t have explicit stubbing instructions, Spock will return default values (false for Boolean variables, 0 for numbers, and null for objects). If you want to make sure that a method isn’t called in a mock, you have to declare it in the then: block as well. Pay close attention to the last statement of the following code listing.

Listing 6.17. Explicit declaration of interactions

There are three important points to notice in listing 6.17 that relate to the three lines in the then: block.

Starting from the bottom, you want to make sure that the basket only queries the warehouse, but never tampers with the stock levels. Therefore, the code explicitly states that you expect zero invocations for the method that fills the inventory.

The middle line verifies that the method of product availability is called twice (because the test deals with two products). Because you want the basket to think that the warehouse is full, you also stub the method to return true both times. Thus the code in this line is both a mock expectation and a predefined stubbed response:[10]

10

This is a big difference from Mockito. In Mockito, you can separately stub a mock and verify it in another statement. In Spock, you do both things at the same time.

2 * inventory.isProductAvailable( _ , _) >> true

This line says to Spock, “After this test is finished, I expect that the method isProductAvailable() was called twice. I don’t care about the arguments. But when it’s called, please return true to the class that called it.”

The last thing to notice is that unlike previous code listings, the canShipCompletely() method is called in the when: block, and only its result is checked in the then: block. The reason for this is that Spock records the interactions of mocks in the when: block (which should always contain the trigger code). When using mocks (or stubs), the then: block must contain only verifications.

6.3.5. Verifying noninteractions for multiple mocked classes

Now you know how to verify individual methods for any number of invocations. But sometimes you want to cast a wider net, and control invocations at the class level instead of the method level. The underscore character is flexible regarding its position inside a verification statement. Consider the following listing.

Listing 6.18. Verifying interactions for all methods of a class

Here you’ve written a strict unit test because it assumes that regardless of the number of methods that exist in the inventory class, the basket class should call only isProductAvailable() and isEmpty() and nothing else. Therefore, the last verification line uses the underscore as a method matcher:

0 * inventory._

This line means, “I expect zero invocations for all other methods of the inventory class.” Be careful when using this technique because it means that you know exactly the interface between the class under test and the mock. If a new method is added in the mock (in the production code) that’s used by the class under test, this Spock test will instantly fail.

If you have multiple mocks, you can write even stricter tests by placing the underscore as a class name, as shown in the next listing.

Listing 6.19. Verifying noninteractions for all mocks

In this code listing, the basket class is injected with two mocks (one for shipping costs and one for the inventory). After running the test, you want to verify that only two specific methods were called on the inventory and that nothing was called for the shipping cost service. Instead of manually declaring all other methods with zero cardinality one by one, you use the underscore character in the class part of the verification. In Spock, the line

0 * _

means, “I expect zero invocations for all other methods of all other classes when the test runs.” Also notice that you don’t care how many times the isEmpty() method is called, and you use the underscore operator in the cardinality:

_ * inventory.isEmpty() >> false

This line means, “I expect the isEmpty() method to be called any number of times, and when it does, it should return false.”

The many faces of the underscore character

As you may have noticed by now, the underscore character is a special matcher for Spock tests. In the basic form of a mock verification, N * class.method(argument), the underscore can be used to match arguments (listings 6.16, 6.17), methods (listing 6.18), classes, and even the cardinality N (listing 6.19). For all these cases, you don’t care about the respective part of the verification.

6.3.6. Verifying types of arguments when a mocked method is called

I’ve shown how to verify specific arguments in mock invocations and how to say to Spock that you don’t care about arguments (the underscore character). But between these two extremes, you can verify several other attributes of arguments. One of the most useful verifications is to make sure that the argument passed isn’t null. This can be described naturally in Spock, as shown in the next listing.

Listing 6.20. Verifying that arguments aren’t null when a mocked method is called

In this listing, you want to make sure that whatever argument is passed to the inventory isn’t null (because the arguments should be names of products). For the second argument, where you know exactly what will be used, you directly put in the value:

2 * inventory.isProductAvailable(!null ,1) >> true

This line means, “I expect that the method isProductAvailable() will be called twice. The first argument can be anything apart from null, and the second argument will always be 1. When that happens, the method will return true.”

In unit tests with complex class hierarchies, you can verify the type of arguments as well. The following listing illustrates this (for this trivial example, verifying the type of arguments is probably overkill).

Listing 6.21. Verifying the type of arguments

Again you use the magic underscore character, this time combined with the as keyword. Notice that a null argument will also fail the verification so the as/underscore combination includes the null check.

6.3.7. Verifying arguments of method calls from mocked classes

Using the underscore character as an argument in your mock verifications means that you don’t care about the argument at all. But what happens if your unit test is focused on the arguments and you do care?

In that case, my advice is to declare exactly what you expect. You’ve already seen that with scalar values, you use them directly as arguments. The same thing happens with full objects, as shown in the next listing.

Listing 6.22. Verifying exact arguments of a mocked method

As you can see in this listing, there’s no special syntax for objects:

1 * creditCardSevice.sale(1550, customer)

This line means, “When the test ends, I expect the sale() method to be called exactly once. Its first argument should be the number 1550, and its second argument should be the customer instance.”

If you want to verify part of an object instance and not the whole instance, you can use Groovy closures in a similar way to stubs (as was shown in listing 6.8). The same syntax applies to mocks, as the following listing shows.

Listing 6.23. Verifying part of an object instance used as a mock argument

The last verification line in this listing checks only the vip field of the customer object. The other two fields (name and creditCard) can be anything, and the test will still pass. With the power of Groovy closures, you can check a mocked argument against any expression you can think of.

Listing 6.24. Using full Groovy closures for argument verification

This listing uses two closures, one for each argument of the sale() method. As before, the second closure checks a single field of an object (the vip field from the customer class). The first closure makes its own calculation with a completely external method, the findOrderPrice():

1 * creditCardSevice.sale({amount -> amount ==
    basket.findOrderPrice()}, { client -> client.vip == false})

The whole line means, “When this unit test is complete, I expect the sale method to be called exactly once. It should have two arguments. The first argument should be equal to the result of basket.findOrderPrice(). The second argument should be an object instance with a vip field. The value of the vip field should be false.”

If any facts of this sentence don’t stand, the Spock test will fail. All of them must be correct for a successful test.

..................Content has been hidden....................

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