• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Bear Bibeault
  • Junilu Lacar
Sheriffs:
  • Jeanne Boyarsky
  • Tim Cooke
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • salvin francis
  • Frits Walraven
Bartenders:
  • Scott Selikoff
  • Piet Souris
  • Carey Brown

What's the best approach for testing lambda expressions?

 
Sheriff
Posts: 11604
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When I look at lambda expressions I wonder what's the best approach/technique to test these expressions. Because you use a very well-designed API/library, you don't want/need to test this library over and over again. You just want to concentrate your testing on the lambda expressions itself.

For example, suppose this simple problem: get all the odd numbers in a list greater than 15 without any duplicates.

What is the best approach to test this code? For this simple example it's probably the easiest to pass a list containing a few different numbers and verify if the resulting set contains the expected numbers. But this will only work for a fairly simple example. If the code gets more complex, this approach will probably result in complex and hard to maintain testing code.

You always strive to 100% test coverage, so you want only to write test cases for your own business logic and once you covered your business logic you can use mocking to verify your program flow, resulting in complete coverage with the least effort (and code) possible. But I doubt if that's possible with the new language constructs in Java 8. Or maybe it's worth to introduce a predicate helper class to improve writing simple tests (although then your code won't be so concise anymore and if you use lots of predicates you'll probably see the forest for the trees).
 
author
Posts: 799
5
  • Likes 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Roel,

I seek to test "through the interface" when unit testing. For your lambda example, I do think it's best extracted as a separate method and tested directly. I might end up with the following cases, each of which is a single-line test:

returnsEmptySetWhenListEmpty
returnsOnlyOddNumbers
returnsOnlyNumbersAboveThreshold
eliminatesDuplicates

There are more simple variants I could code if I felt I needed the confidence.

I'm not testing a lambda--that's an implementation detail. I could re-code your expression with classic loop structures, and it should pass the same tests I designed around the interface to the desired behavior.

The code will get more complex, most likely! That's where having tests really pays off--they will prevent you from breaking stuff that already works when you make changes. The more complex the code, the more useful it is to have the confidence that the tests can give you.

Separating things to separate Predicates can both make it easier to test and also to understand client code. I've not seen it be a problem. You might find a bit of additional reuse, and therefore shrink your code, by doing so.

Regards,
Jeff
 
Roel De Nijs
Sheriff
Posts: 11604
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Jeff Langr wrote:I seek to test "through the interface" when unit testing. For your lambda example, I do think it's best extracted as a separate method and tested directly. I might end up with the following cases, each of which is a single-line test:

returnsEmptySetWhenListEmpty
returnsOnlyOddNumbers
returnsOnlyNumbersAboveThreshold
eliminatesDuplicates

There are more simple variants I could code if I felt I needed the confidence.

I'm not testing a lambda--that's an implementation detail. I could re-code your expression with classic loop structures, and it should pass the same tests I designed around the interface to the desired behavior.


That's a very nice approach of the "problem". And with this simple example, it's probably the best approach as well. But I wonder if it's feasible if your code gets more complicated (e.g. when it's hard to assemble test objects because of its complex object graph). In our current project our tests heavily rely on mocking and that's probably why I'm focusing on being able to mock this predicate, while in this context/method that's completely unneeded. The reason why we use mocking is because you don't have to worry about actual values, you can use dummy values and let them behave like you want.

A simple example: assume you'll have a utility method isEmpty(String s) which returns true if s is null, empty or whitespace; false otherwise. And you need to test this method:Will you write tests for empty type values like null, "" and " "? Or do you mock the isEmpty call returning true if you pass "ty0" and false with all other values?

Jeff Langr wrote:The code will get more complex, most likely! That's where having tests really pays off--they will prevent you from breaking stuff that already works when you make changes. The more complex the code, the more useful it is to have the confidence that the tests can give you.


True! Having tests allows you to refactor your code and still be confident you didn't break stuff that was working perfectly. And if it's difficult to test some code, it's most of the time an indication you should re-think your code and choose another design/approach. This way writing tests even improves code quality.

Jeff Langr wrote:Separating things to separate Predicates can both make it easier to test and also to understand client code. I've not seen it be a problem. You might find a bit of additional reuse, and therefore shrink your code, by doing so.


It will probably speak for itself once I start coding/using lambdas and predicates
 
Jeff Langr
author
Posts: 799
5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Roel De Nijs wrote:A simple example: assume you'll have a utility method isEmpty(String s) which returns true if s is null, empty or whitespace; false otherwise. And you need to test this method:Will you write tests for empty type values like null, "" and " "? Or do you mock the isEmpty call returning true if you pass "ty0" and false with all other values?



Hi Roel--

Right--if you assume that isEmpty is already tested (I wrote unit tests for it elsewhere), the job in testing the create method is to verify the two possible paths based on the two possible outcomes of the if conditional. As you suggest, you could mock the static (if you were using, for example, PowerMock). You could also set the value of type to a value that answers false for the conditional for one test, and to a value that answers true for a second test. Those two tests, perhaps named:

createReturnsNullWhenTypeIsEmpty
createReturnsAnimalWhenTypeNotEmpty

are sufficient, since isEmpty is already tested. Any more tests around how type might be "empty" would be redundant.

I think I lean toward using mocks if the tool is right (probably Mockito--i.e. a tool where I can clearly express the stubbing in a single line) and it's not a static (I don't like the extra complexity of bringing in PowerMock). Otherwise, I'm ok with passing a representative value. The test names are the same either way.

Jeff
 
Roel De Nijs
Sheriff
Posts: 11604
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Jeff Langr wrote:Right--if you assume that isEmpty is already tested (I wrote unit tests for it elsewhere), the job in testing the create method is to verify the two possible paths based on the two possible outcomes of the if conditional. As you suggest, you could mock the static (if you were using, for example, PowerMock). You could also set the value of type to a value that answers false for the conditional for one test, and to a value that answers true for a second test. Those two tests, perhaps named:

createReturnsNullWhenTypeIsEmpty
createReturnsAnimalWhenTypeNotEmpty

are sufficient, since isEmpty is already tested. Any more tests around how type might be "empty" would be redundant.


I fully agree! But although mocking the static adds more complexity (and code), I prefer this approach, because I feel more safe (giving me more test coverage).

Assume you opt for those 2 tests and you set the value of type to null (will result in true) and to "type1" (will result in false). Both tests run successfully and everybody's happy. But then someone changes the code of the create method toBoth tests will still run successfully. Would you not expect/want for at least one of the tests to fail, because this code change will introduce a potential bug which isn't detected by your unit tests?

Kind regards,
Roel
 
Jeff Langr
author
Posts: 799
5
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Roel--

Indeed that's a possibility, though in practice unlikely, and I'm struggling to think of a case where I've seen something like that happen (I'm sure it has for me).

There are lots of folks expounding on this in various places if you search; for example, http://butunclebob.com/ArticleS.UncleBob.TheDangerOfMockObjects

I think there's a balance to be stricken. I found that I didn't enjoy mocking *every* collaborator call when I've tried it--it leaned toward too much pain when I wanted to refactor.

Regards,
Jeff
 
Marshal
Posts: 15876
265
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Some things I have done in the past when mocking becomes painful because of too many collaborators:

1. Try to move some of the collaborators away from the class under test, perhaps make them indirect collaborators in the production code. That way, instead of four collaborators, you only have one and that one will be dependent on the other three previously direct collaborators. The one collaborator essentially becomes a Facade.

2. See if the collaborators are really needed or if you can move the responsibilities/behavior you're interested in from the collaborators into the class under test. Sometimes it's a mis-assigned responsibility that's the problem.

3. Just create the collaborators from the class under test. Sometimes you don't need all those layers of abstraction and loose coupling, especially if the interactions don't cross major system/module boundaries.
 
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I get the impression that you're concentrating on testing at a too granular level. You should rarely ever want to test a single method on it's own. If it's some mathematics then I can understand that because you need to validate your algorithm - but in that case I'm not sure a lambda is the best place for it anyway. Those inline lambdas are a nice syntax for brevity when doing simple things. If you cram a load of logic into them then you're possibly kindof going against the point if them in the first place.
 
    Bookmark Topic Watch Topic
  • New Topic