A long time ago (year 2000), the mock objects were
invented. It is now one of the most important parts of unit testing.
For those you don’t know, the idea of a mock object is to simulate a dependency to easily test a class. Quick example.
I have a class Pricer.
publicclassPricer{privatePriceFeedpriceFeed;publicBigDecimalgetPrice(Stringsymbol){BigDecimallatest=priceFeed.getLatestPrice(symbol);// ... do some calculations ...returnvalue;}}
Being a nice human being, I want to test my calculations but I don’t want to use a real PriceFeed. The real implementation
has to an actual MQSeries queue that received prices from Reuters. It’s not something you want to do during your unit tests
(if at all).
So you will instead do a mock object, an object that will behave as you see fit for your test but that isn’t a real PriceFeed. It just
mimics it.
Not so long ago, Uncle Bob did a blog post about mock objects. He classifies
them into five different types or levels. Levels because each type is wiser than the previous one. He calls them “Test Doubles”.
I’ve decided to show you how to code them. Using EasyMock (of course), Mockito and by hand.
Type of mocks
From the most basic to the most advanced type.
Dummy
A class that you pass into something when you don’t care how it’s used. e.g. As part of a test, when you must pass an
argument, but you know the argument will never be used.
In this EasyMock world, it is called a nice mock (Authorized mock = niceMock(Authorized.class)).
In the Mockito world, it’s just a mock (Authorized mock = mock(Authorized.class)).
In general, if a dummy is used, you will want it to throw an exception to tell you something is
wrong. So, with Mockito, you will in general get a NullPointerException (or not) if you do something like
if(mock.authorize(user, password)) // NPE
With EasyMock, you will generally prefer to use a normal mock (Authorized mock = mock(Authorized.class)) that
will make sure nothing unintended is called.
In EasyMock, it means you are not stubbing anymore. You want to record a precise call (expect(mock.authorize(anyString(), anyString()).andReturn(true))
and then verify that the call actually occurred (verify(mock)).
In Mockito, you still stub the call and then verify the call occurred (verify(authorizer).authorize(any(), any())). Note that Mockito has its own
concept of a spy, which is different. A Mockito spy is a shell over an actual class that allows to verify calls to them. It is indeed useful
but it isn’t a mock. So don’t get lost in the semantic.
True Mock
A true mock is a mock that knows how to verify itself. In fact, EasyMock and Mockito mocks are always true mocks. So their
implementations of a true mock is the same as for the spy.
A Fake has business behavior. You can drive a fake to behave in different ways by giving it different data. They are usually
used for integration testing to simulate other parts of your system.
When jumping from one flavor to another, you should make sure you really need to. Because the more complicated your
mocking is, the more coupling you will have with the actual implementation. It makes the test more fragile. But you
still need to make sure everything is working as expected!
Testing advice
Modify to test
If your code isn’t easy to test, modify your code. Do whatever is needed. You will end up with a better design
anyway. A test should not be complicated. If it needs to, something is wrong.
Provide a testing framework
If you build something, you should provide a nice framework to test it. Spring has spring-test. You are
responsible for making what you do testable, mockable, etc.
Use as less mocks as possible
Usually, unit tests should use at worst 3 mocks. It you have more, you probably should split your code in
smaller parts. A lot of mocks makes the code unreadable.
Explain and document your tests
Tests are harder to understand than actual production code. When someone reads test code, he should understand
the purpose. So use a nice test name to explain what you wanted to do. Use javadoc. Use line comments to explain the flow.
Refactor them
I’m refactoring my tests a lot. A lot. Nice methods preventing copy & paste. Testing frameworks. Fixtures. Base test
classes. Everything to make it as pretty as my production code.
I felt on some code yesterday and had to think a bit about it before deciding that it wasn’t working as expected. And then went on to
wonder if I could make it work. I found it interesting so I thought I should tell you about it.
@TestpublicvoidtestListGetsFilled()throwsException{List<String>list=Collections.emptyList();CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(!list.isEmpty()){returnlist.size();}}});// ... do some async task that should fill the list in less than 1 second ...assertThat(future.get(1,TimeUnit.SECONDS)).isGreaterThan(0);}
So. What’s going on here?
We have a list
A CompletableFuture is waiting for the list to be filled
We wait on the future until is has finished
If it takes too long, we timeout
It works. If the list is filled, the test will be successful, if the list is never filled, the get will timeout after
1 seconds (throwing a TimeoutException) and the test will fail.
The only problem is that if the test does fail, the future task itself will never finish. It is still stuck in the while
loop.
Why?
Because nothing can stop it. supplyAsync is submitting a task to the common pool. This task will run in a thread we are
not managing. The task won’t stop until the list isn’t empty anymore. That’s it.
A timeout of the CompletableFuture won’t change anything. It just means that we are not waiting on the get anymore. But
it has no power over the task itself.
What can we do?
Maybe we can interrupt it? Let’s try.
@TestpublicvoidtestListGetsFilled_withInterrupt()throwsException{List<String>list=Collections.emptyList();CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(!list.isEmpty()){returnlist.size();}try{Thread.sleep(1);}catch(InterruptedExceptione){return0;}}});// ... do some async task that should fill the list in less than 1 second ...assertThat(future.get(1,TimeUnit.SECONDS)).isGreaterThan(0);}
In the original loop, nothing could be interrupted. Now we introduce a sleep. It can be interrupted. However, it won’t.
The timeout on the get doesn’t trigger an interrupt on the thread running the task.
That doesn’t work either?
Can it be cancelled you say?
@TestpublicvoidtestListGetsFilled_cancelled()throwsException{List<String>list=Collections.emptyList();AtomicReference<CompletableFuture<Integer>>ref=newAtomicReference<>();CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(ref.get()!=null&&ref.get().isCancelled()){returnlist.size();}if(!list.isEmpty()){returnlist.size();}}});ref.set(future);// ... do some async task that should fill the list in less than 1 second ...assertThat(future.get(1,TimeUnit.SECONDS)).isGreaterThan(0);}
Here the code is a bit more complicated. We can’t access the future from the lambda directly. Because the lambda starts
before the assignment is made. So we use an AtomicReference, wait until its content isn’t null anymore and then wait
for cancellation… that never arrives.
Yes. The timeout on the get won’t trigger a cancellation. This is on purpose. There is nothing preventing you from waiting
a bit on the get, do something else, and come back to get again.
Enough of that! Tell me what works!
OK. OK. Calm down. I’ll show you but it’s not pretty.
@TestpublicvoidtestListGetsFilled_cancelledForReal()throwsException{List<String>list=Collections.emptyList();AtomicReference<CompletableFuture<Integer>>ref=newAtomicReference<>();CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(ref.get()!=null&&ref.get().isCancelled()){return0;}if(!list.isEmpty()){returnlist.size();}}});ref.set(future);// ... do some async task that should fill the list in less than 1 second ...try{future.get(1,TimeUnit.SECONDS);}catch(TimeoutExceptione){future.cancel(false);}assertThat(future.get()).isGreaterThan(0);}
So now we are cancelling the task ourselves. That works. The task correctly finishes. One funny thing to mention is that the
assert won’t fail. In fact, it’s the call to future.get() in assertThat that will throw a CancellationException and
make the test fail.
OK. We now have a pretty ugly and complicated solution that works.
Can we simplify?
You might have noticed that cancel() take a parameter named mayInterruptIfRunning. That sounds promising! We can get
an interruption! Let’s try.
@TestpublicvoidtestListGetsFilled_cancelledToInterrupt()throwsException{List<String>list=Collections.emptyList();CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(Thread.interrupted()){System.out.println("Done");return0;}if(!list.isEmpty()){returnlist.size();}}});// ... do some async task that should fill the list in less than 1 second ...try{future.get(1,TimeUnit.SECONDS);}catch(TimeoutExceptione){future.cancel(false);}assertThat(future.get()).isGreaterThan(0);}
No atomic reference anymore. But doesn’t work. The task doesn’t get interrupted. If I quote the javadoc for cancel():
mayInterruptIfRunning this value has no effect in this implementation because interrupts are not used to control processing.
Basically, that means CompletableFuture are not supposed to be interrupted. They are at a higher level of abstraction.
Here is the nicest solution I know about.
@TestpublicvoidtestListGetsFilled_cancelledByFlag()throwsException{List<String>list=Collections.emptyList();AtomicBooleancancelled=newAtomicBoolean(false);CompletableFuture<Integer>future=CompletableFuture.supplyAsync(()->{while(true){if(cancelled.get()){returnlist.size();}if(!list.isEmpty()){returnlist.size();}}});// ... do some async task that should fill the list in less than 1 second ...try{future.get(1,TimeUnit.SECONDS);}catch(TimeoutExceptione){cancelled.set(true);}assertThat(future.get()).isGreaterThan(0);}
Yes, it’s just a simple flag. But it works nicely.
Still, you might ask me: “Why is it that complicated?”
In fact, I’m not totally sure. I think CompletableFuture are not meant to be used like this. They are supposed to
complete. Or to fail exceptionally. Normal Future are the ones that are supposed to loop like that.
But I’ll need more digging to be more conclusive. Right now, I only wanted to share my How to cancel a CompletableFuture?
discovery.
I was at JCrete two weeks ago. For those who don’t know, it is an awesome Java unconference where everyone with
their family to talk about Java. It has been created by Heinz Kabutz a.k.a The Java Specialist. I was
really happy to see a bunch of heads I haven’t seen since moving back to Montreal.
One of the sessions I’ve led was about data visibility according to the JMM. I didn’t care about
lock and synchronization. Just data visibility.
If I write to this variable, will this other thread see the new value for sure?
I was lucky enough to gather with a handful of subject matter experts.
My goal was to give really simple examples of what works or not. The final code can be found on
JCrete’s github.
But I will still describe it here. It’s based on the concept of “Will the thread ever get out of the loop?”. All the examples are almost identical.
If the field visibility is correct, when the main thread flips the field, the child thread will see the value and correctly exit the loop. If
it’s not, the thread might go in an infinite loop according to the JMM. I’m saying “might” because depending on the CPU architecture,
JVM version and the way the wind is blowing, it might see the value correctly on your machine. That doesn’t mean it will work ever after.
I recommend that you first guess the result before looking at the answer.
The first example is a normal field (no final or volatile) without any kind of synchronization.
Volatile ensure data visibility. When a volatile field is changed, all other threads are seeing the value right away. Volatile tells the JVM
that the value shouldn’t be kept local to the thread.
Of course it works. Data visibility of the content of an atomic is guaranteed. Note, however, that it doesn’t apply to the field referencing
the atomic field (stopAtomicField). It still works on our case because we assign (stopAtomicField = new AtomicBoolean()) before starting
the thread. The JVM makes sure a starting thread will see everything that happened-before.
By the way, watch out for lambda and inner classes. They don’t have the same this. For a lambda, this is the class where the lambda is
defined. For an inner class, it is the inner class.
@TestpublicvoidsynchronizedInnerClassField(){newThread(newRunnable(){@Overridepublicvoidrun(){while(true){synchronized(DataVisibilityTest.this){// Specify the this from the outer classif(stopNormalField){break;}}}System.out.println("Done");}}).start();synchronized(this){stopNormalField=true;}}
Does it work: Yes
Synchronization works. Fair enough. But can I use a lock? I was told locks are better than synchronization.
Locking provides the same data visibility as synchronizing.
In fact, all JUCs are providing the necessary memory barriers to get the correct visibility. Below, countDown and await will make sure
the child thread sees the world correctly.
As soon as you use JUC abstractions, things tend to magically work in fact. Which is a good thing even though everything magically working
is always a bit frightening.
OK. We will finish this post with the Don’t do this at home example. It means it is trickier to get right and you won’t need it for business
as usual.
Here we cause the synchronization of the normal field by using a volatile field. Writing to stopVolatileField causes a happens-before
relationship. Happens-before is JMM jargon. It has a script definition. That means what it means in English. That you are sure something
happened before. In our case, it means the value written to stopNormalField will be seen by the child thread after it reads stopVolatileField.
Thanks again to all the contributors to this session (you will find some of them on the
readme.
Objenesis went out last week partly because Google App Engine is now supporting Java 8 in
beta. And they are no security manager anymore preventing Objenesis to work.
The problem was that Objenesis was checking if it was running on GAE to pick an instantiating strategy. So it was still running in degraded
more on GAE Java 8. It is now fixed.
However, Spring uses an embedded version of Objenesis. So they need to upgrade. Luckily, they are super fast to do so. You can follow the
issue but it will be in Spring 4.3.10 and Spring Boot 1.5.5.
Meanwhile, you might be eager to test your shiny new app on this new Google App Engine platform and would be really happy to make it work.
I have a solution for you. It isn’t pretty but it works.
In Java, in case you don’t know, you just need to put your class file in front of another one in the classpath to “shadow” it. It means your
class will be used instead of the original implementation. In a war, everything in WEB-INF/classes goes before WEB-INF/lib. So you can
easily shadow a class.
That’s what I did. My SpringObjenesis.java
version shadows Spring one. It delegates to the real Objenesis implementation instead of the Spring embedded one. You only need to add the latest
Objenesis (2.6) as a dependency to your project.
An all new shiny Objenesis is out. The framework everybody uses without even knowing it.
It had fun playing with the brand new Google App Engine platform supporting Java 8. They dropped the terrible security manager they used to
have to know Objenesis is working perfectly on it. This was brought to my attention by GAE developers. They are now testing mainstream frameworks
on their platform to make sure it works. This should make GAE adoption easier.
Java 9 was pretty much already working but I got rid of all the “Illegal accesses”. Not that obvious since in Objenesis, this is how we roll.
Finally, a bit of cleanup in the serialization specification was done. So now a serializing instantiator should instantiate a class by calling
the no-arg constructor of the first non-serializable class in the hierarchy. And do nothing else. See the documentation
for details.
I’ve mentioned already why I am now using a mac after years of beloved Windows.
But I’m still complaining about the really bad UI behavior of macOS (I’m on Sierra). And the ca_fr keyboard that should have had the exact
same layout that Windows had for years instead of trying to be wiser… But that’s hardware so there’s nothing I can do about it.
First, one of the first thing I’ve fixed is the random behavior of Home and End keys. By default, depending on the app you are in, the behave
differently. This is plainly insane. Here is the fix:
cd ~/Library
mkdir KeyBindings
cd KeyBindings
vi DefaultKeyBinding.dict
Put these lines in that file, including the curly braces:
{
/* Remap Home / End keys to be correct */
"\UF729" = "moveToBeginningOfLine:"; /* Home */
"\UF72B" = "moveToEndOfLine:"; /* End */
"$\UF729" = "moveToBeginningOfLineAndModifySelection:"; /* Shift + Home */
"$\UF72B" = "moveToEndOfLineAndModifySelection:"; /* Shift + End */
"^\UF729" = "moveToBeginningOfDocument:"; /* Ctrl + Home */
"^\UF72B" = "moveToEndOfDocument:"; /* Ctrl + End */
"$^\UF729" = "moveToBeginningOfDocumentAndModifySelection:"; /* Shift + Ctrl + Home */
"$^\UF72B" = "moveToEndOfDocumentAndModifySelection:"; /* Shift + Ctrl + End */
}
Then, macOS is lacking Windows docking. So I’ve installed BetterTouchTool for that.
Back to complaining. Here are the things I wasn’t able to fix so far.
Cmd+Tab should bring to front the requested window. Always. It doesn’t matter if the window is minimized, in background or whatever. Just bring it in front
Cmd+Tab should bring the last used window of an application to the front. Not my 6 Chrome windows. Only the latest one
Cmd+ù should behave as Cmd+` when using a ca-fr keyboard. I can probably use the remap trick for that. I tried BTT, it doesn’t work
When switching desktop, it shouldn’t matter where my mouse is. Especially to access the dashboard. It should just switch all screens. It there a shortcut to switch screen 1?
Cmd+X should cut everywhere. Cmd+C and then Cmd+Alt+V is just not the way my brain works. I think about copy or cut when seeing the file. Not when pasting it. Am I the only one?
I use 2 keyboard layouts (US-en and CA-fr). Because of the dumb keyboard. macOS should remember which application is using which keyboard. However, I don’t need it for each Chrome tab
When living in France, I started to help Devoxx4kids France a little bit. I think
it is an amazing idea that will give kids skills that they will definitely needs later.
It also shows them that Facebook on your phone hasn’t appeared by magic. It took a lot of people for hundred of years
to discover and master the required technologies.
Now that I live in Montreal, I’ve joined Devoxx4kids Québec. Last time I’ve brought my
3 years old. He played with a LEGO Mindstorm robot he built. I was amazed to see him enjoy it even though Mindstorm are 10+.
Anyway, all this is not the theme of this post :-)
This is a post that will evolve in time where I want to put all the cool learning tools I’ve encountered. And try to comment on them.
This is mostly a selfish post that will prevent me from forgetting things. But you might found it useful. So here we go.
Minecraft: Building, creating and programming worlds
Robots
Blue-Bot: A cute mouse that can be programmed directly or from a tablet to follow a path
Code & Go Robot mouse: Similar to Blue-Bot but comes with tiles and obstacles. The mouse can’t be programmed from a tablet. There are cards to tell the path and it recognizes a cheese at the end. Pretty fun
mBot: Little robot on wheels that you can program using Scratch. Uses a bit too much batteries and in fact can’t do much
Ozobot: Little robot that you can program with color markers
UPDATE (2017-02-15): Spring is correctly handling the null from getMissingCache. So you won’t have to overload it. I was misled
by a framework that was incorrectly layering the JCacheCacheManager. I stand corrected and the article as well. Thanks to
Stéphane Nicoll for his vigilance.
UPDATE (2017-02-16): Spring has a JCacheCacheConfiguration that configure a JCache CacheManager using a list of cache names and a
default cache configuration. By default, it uses new MutableConfiguration<>() so the article was updated accordingly.
UPDATE (2017-04-07): My Hibernate PR has been accepted. So you now have an elegant
solution with the latest Hibernate versions. The article was updated accordingly.
I played a lot with JCache connectors lately. To plug Ehcache 3 to different things.
I noticed one really dangerous thing. Frameworks tend to spontaneously create caches that were not explicitly defined. I
think it is coming from the JCache spirit that there should be a default cache configuration. It is nonetheless a bad idea.
Let’s look at two examples
Spring
Caching in Spring is implemented by spring-cache. To plug JCache to spring-cache you use the JCacheCacheManager. By default
when a cache isn’t available in the CacheManager, Spring calls JCacheCacheManager.getMissingCache. So far so good.
The default implementation for this method returns null when a cache doesn’t exist. This null will then be handled at
higher levels to throw a nice exception.
If you want to explicitly support spontaneous cache creation, getMissingCache is where you should put your creation code.
However, watch out if you do that. You might lost track of all the existing caches. And please, never do the following.
It returns a cache configured using default. It is never what you want.
Then, as usual, Spring tries to be nice with us. So if you enable caching (@EnableCaching), that the JSR-107 API is in
the classpath and that you do not expose any CacheManager, Spring will create one for you.
The JCacheCacheConfiguration will get a default JSR-107 CacheManager and add a list of caches taken from the cache property
spring.cache.cache-names. These caches are by default created using a new MutableConfiguration<>(). As we said above, this
is not a correctly configured cache.
The solution is to expose the wanted cache configuration in a bean.
This bean will be magically used as cache default. You should always do this and never let ``new MutableConfiguration<>()`
be used.
Hibernate
To use JCache with Hibernate we need to use the JCacheRegionFactory. The problem with JCacheRegionFactory is that by
default if a cache is not found, it will spontaneously create a cache by passing new MutableConfiguration(). This means
that instead of using a properly configured cache, you end up with some random default configuration (infinite on heap for
Ehcache).
This is really bad because it is pretty hard to detect.
What I recommend in this case is, again, to override the default. In the latest Hibernate versions (5.2.8+) (thanks to
https://github.com/hibernate/hibernate-orm/pull/1783[HHH-1783], we can do the following
In older versions, sadly, there is no straightforward cache creation method to override. The best we have is
newDefaultConfig which provides the default configuration. One sad thing is that you don’t have the actual cache name
here. You will need to debug to know it.
Again, an alternative solution would be to provide a meaningful default cache configuration in this method.
Conclusion
I do understand that frameworks do not like to fail with exceptions. This helps the feeling that they are working out of
the box.
But I still think silently not caching or providing random default configuration is dangerous. Using my two workarounds should
prevent you a lot of headaches.
The get method first look at the state, if done, it just returns. If not, then it interrupts. Here we go,
job done.
Then it goes to the Continuous Integration. And goes in an infinite loop. Whaaat???
At first I thought it was some race condition that was happening with other tests (they are run in parallel).
But no. The answer is much simpler than that: JDK 6
The FutureTask code above is from JDK 8. The JDK 6 code is different. It first starts to check the
interrupt. So infinite loop it is.
Now, was is the right idiom for an uninterruptibleGet?
To get the long answer, I highly suggest that you go read Java Concurrency in Practice
(chapter 7) right now. It is a must read for any Java programmer.
And there’s no way to get around it. Here are some attempts:
List<String>list=mock(List<String>.class);// no allowed (won't compile)List<String>list=EasyMock.<String>mock(List.class);// won't compile either because the parameter type doesn't match)List<String>list=(List<String>)mock(List.class);// still get a warning
So what’s the way out?
To be less accurate.
Yes. I can’t see any other way out. (Do you?)
So my plan is to change EasyMock typing with this:
publicstatic<T>Tmock(Class<?>toMock)
No relation anymore between the parameter and the returned type. WAT!!! Are you crazy?!?
So yes, this will compile without complaints :-( (but I can check the type coherence at runtime)
Stringlist=mock(Integer.class);
But this will now work without any warning :-)
List<String>list=mock(List.class);
You can’t have your cake and eat it it seems. But as usual, I will be happy to be proved wrong.