Why doesn't EclEmma cover syncronized(MyClass.class)?
Asked Answered
N

3

8

I'm using EclEmma for coverage analysis.

My Java code includes a synchronized(MyClass.class) {} block.

EclEmma says it is only partially covered, event though I've got a unit test in which one thread gets access and another thread is blocked.

Is it possible to get full coverage of synchronized using EclEmma?

Can I annotate the code in some way to tell EclEmma to give this line full coverage?

Kind regards Roger

Necessitous answered 15/9, 2010 at 6:34 Comment(0)
E
7

I am not sure it is possible to get a full coverage, since issue 2939804 reports:

EMMA always marks synchronized(..) as partially covered

Examples:

synchronized (lock) // partially covered (yellow line in EclEmma)
{
// ...
}
synchronized (this) // partially covered (yellow line in EclEmma)
{
// ...
}

Maybe a different tool (like Cobertura) would yield a different result? (I have not tested it recently).


Update December 2012 (more than 2 years later):

Nathan D Ryan reports:

synchronized will light to green if the synchronized block contains code that waits on an object monitor, and a test interrupts the waiting thread.

After a little experimentation, I was able to achieve complete coverage of the synchronized line if the synchronized block completed normally and completed abruptly due to an exception.

Eiger answered 15/9, 2010 at 6:38 Comment(5)
It seems like you are right. I tried this: Object synch = MyClass.class; synchronized (synch) {} but it didn't help, even though my test has one thread waiting and another thread getting the mutex.Necessitous
In my experience, synchronized will light to green if the synchronized block contains code that waits on an object monitor, and a test interrupts the waiting thread. I've never bothered to dig into the EMMA instrumentation to find out whether this is true in the general case, however.Canorous
After a little experimentation, I was able to achieve complete coverage of the synchronized line if the synchronized block completed normally and completed abruptly due to an exception.Canorous
@NathanD.Ryan interesting. I have included your comment in the answer for more visibility.Eiger
@NathanRyan Can you please share an example?Haplography
M
1

EclEmma uses Jacoco underneath for the coverage analysis.

As explained in Jacoco's (currently non-existing) JAVAC.SYNC filtering option, the behavior is a result of the byte code generated for synchronized blocks:

A Java synchronized block gets compiled into two bytecode instructions: MONITORENTER at the beginning and MONITOREXIT at the end of the block.

To ensure that the the monitor is released in any case an exception handler is installed which points to another MONITOREXIT instruction. This exception handler block typically causes partial line coverage which doesn't make sense from the source code point of view.

A related Jacoco issue 245 explains how exceptions can be triggered to reach full coverage, should this be desired, as also explained by @nathan-ryan:

  1. One test that executes the synchronized block normally
  2. A second test that throws (and hence expects) an exception from within the synchronized block.
Marmara answered 1/6, 2016 at 11:18 Comment(1)
(Hi Arie). So Jacoco doesn't understand that the control flow is safe: if you reach the entry point, you will reach the exit point. I imagine that a block with local variables is compiled into a block that initializes the locals, executes the body, and cleans up the locals, with an additional implicit exception handler wrapped around the block that cleans up the locals in case of an exception. That seems exactly the same in style; yet you can get full coverage on a block by "executing through" it. (Our Java test coverage tool instruments the source code and wouldn't be confused).Updraft
N
0

I believe the problem is MyClass.class which apparently is implemented using

http://emma.sourceforge.net/faq.html#q.fractional.examples

Implicit branches due to a hidden Class.forName(). This case is rather unfortunate because it is pretty common and yet the programmer has almost no control over it.

Because Class.forName() can throw checked exceptions, the compiler emits a catch block that rethrows them as unchecked. This catch block hardly ever executes in practice, but it succeeds in marking the line as partially covered.

I missed that on the first read-through.

I will try to re-write my code to get full coverage.

/Roger

Necessitous answered 15/9, 2010 at 7:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.