Written on June 01, 2016
Usually, when writing a unit test you call a method in your test code that gets called in your application. Given some inputs and possibly test doubles, you call these methods to test a certain behavior happening and then specify the changes you expect to result from this behavior.
Lambda expressions pose a slightly different challenge when unit testing code. Because they don’t have a name, it’s impossible to directly call them in your test code. You could choose to copy the body of the lambda expression into your test and then test that copy, but this approach has the unfortunate side effect of not actually testing the behavior of your implementation. If you change the implementation code, your test will still pass even though the implementation is performing a different task.
There are two viable solutions to this problem. The first is to view the lambda expression as a block of code within its surrounding method. If you take this approach, you should be testing the behavior of the surrounding method, not the lambda expression itself.
Here’s an example method for converting a list of strings into their uppercase equivalents.
The only thing that the lambda expression in this body of code does is directly call a core Java method. It’s really not worth the effort of testing this lambda expression as an independent unit of code at all, since the behavior is so simple.
If I were to unit test this code, I would focus on the behavior of the method. For example, here is a test that if there are multiple words in the stream, they are all converted to their uppercase equivalents.
Sometimes you want to use a lambda expression that exhibits complex functionality. Perhaps it has a number of corner cases or a role involving calculating a highly important function in your domain. You really want to test for behavior specific to that body of code, but it’s in a lambda expression and you’ve got no way of referencing it.
As an example problem, let’s look at a method that is slightly more complex than con‐ verting a list of strings to uppercase. Instead, we’ll be converting the first character of a string to uppercase and leaving the rest as is. If we were to write this using streams and lambda expressions, we might write something like the following.
Should we want to test this, we’d need to fire in a list and test the output for every single example we wanted to test. The test below provides an example of how cumbersome this approach becomes. Don’t worry—there is a solution!
Don’t use a lambda expression! I know that might appear to be strange advice in an article about lambda expressions, but square pegs don’t fit into round holes very well. Having accepted this, we’re bound to ask how we can still unit test our code and have the benefit of lambda-enabled libraries.
Do use method references. Any method that would have been written as a lambda expression can also be written as a normal method and then directly referenced elsewhere in code using method references. In the code below I’ve refactored out the lambda expression into its own method. This is then used by the main method, which deals with converting the list of strings.
Having extracted the method that actually performs string processing, we can cover all the corner cases by testing that method on its own. The same test case in its new, simplified form is shown here:
The key takeaway here is that if you want to unit test a lambda expression of serious complexity, extract it to a regular method first. You can then use method references to treat it like a first-class function.
If you are interested in an intensive Java 8 training, check out our Modern Development with Java 8 training two-day course