I am trying to test some code inside lambda expression which is a call back from another class.
class EmailSender {
private EmailBuilder emailBuilder;
public void send() {
String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
//send testEmail
}
private Consumer<Email> bodyContentAppender() {
//how to test this through JUnit?
return email -> email.appendBody("Body Content");
}
}
interface EmailBuilder {
String buildEmail(String templateName, Consumer<Email> contentAppender);
}
The lambda expression in the method getBodyContent
is called from EmailBuilder
which is a mocked dependency in the JUnit test for EmailSender
. Since I am mocking the behavior of EmailBuilder
, the code inside getBodyContent
is not called from tests. How to test such piece?
EDIT:
Capturing the lambda expression through Argument Captors is not a solution in this case as the behavior of EmailBuilder
is mocked and the actual methods are not called. Secondly, email.appendBody
does some transformations on an object which is passed by an external API and not straightforward to create.
Unit Testing Lambdas The unit testing with complex lambdas, similar to unit testing of stream pipelines, can be simplified with following practices: Replace a lambda that needs to be tested with a method reference and an auxiliary method. Then, test the auxiliary method.
We use lambda functions when we require a nameless function for a short period of time. In Python, we generally use it as an argument to a higher-order function (a function that takes in other functions as arguments). Lambda functions are used along with built-in functions like filter() , map() etc.
C++ Lambda expression allows us to define anonymous function objects (functors) which can either be used inline or passed as an argument. Lambda expression was introduced in C++11 for creating anonymous functors in a more convenient and concise way.
Lambda expressions are a new and important feature included in Java SE 8. They provide a clear and concise way to represent one method interface using an expression. Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection .
What you are trying to do here is essentially to verify that a factory method did in fact really return the correct object. There is this related question, where the consensus is to not test the result of a factory method beyond verifying that it does indeed return an object of the correct type. The behavior of that object should be tested in the UnitTests for that type.
In an answer to this related question on unit testing lambdas Stuart Marks argues that
If the code in the lambda is complex enough that it warrants testing, maybe that code ought to be refactored out of the lambda, so that it can be tested using the usual techniques.
Now, the real question is: If this was not a lambda, but a concrete class MyBodyContentAppender
that implements the functional interface Consumer<Email>
, how would you unit test that? What kinds of test would you write for this class?
You would probably write tests to verify that, given an Email
, invoking accept()
does indeed invoke appendBody()
with the appropriate parameters, perhaps that invoking it with a null
argument throws a NullPointerException
etc. You would possibly not verify that email.appendBody()
works as expected, because that is covered by the tests for Email
. You may have to mock Email
for these tests if it is difficult to create.
Well, all of these tests can also be performed for the lambda. Your problem is that the factory and the type of the created object are both private, so from the perspective of your test, the only way to access that object is via the parameter passed to the (mocked) emailBuilder.buildEmail()
.
If you use Mockito for mocking the emailBuilder
, you could capture the arguments to this method via ArgumentCaptor
s (see 15. Capturing arguments for further assertions (Since 1.8.0)), I'm sure other mocking libraries provide similar functionality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With