Cobertura Interview Questions -1
Where does the name “Cobertura” come from?
“Cobertura” is the Spanish and Portuguese word for “coverage.” We were trying to avoid acronyms and coffee references. It’s not too hard to associate the word “cobertura” with the word “coverage,” and it even has a bit of a zesty kick to it!
What is Vobertura?
Cobertura is an open source tool that measures test coverage by instrumenting a code base and tracking the percentage of code that are executed as the test suite runs. It is based on jcoverage. In addition to identifying untested code and locating bugs, Cobertura can optimize code by flagging dead and unreachable code. Cobertura monitors tests by instrumenting the bytecode with extra statements to log which lines are and are not being reached as the test suite executes. It then produces a report in HTML or XML that shows exactly which packages, classes, methods, and individual lines of code are not being tested.
What about Emma?
We haven’t used it very much, but it looks like it does a pretty good job. Judging from the sample on the Emma web page, we think the Cobertura HTML reports are a bit easier to digest. It looks like Emma has some nice usability features, such as the ability to instrument all classes in a jar file with one command. A little friendly competition never hurt anyone.
What do I need to use Cobertura?
A computer with Java 1.3 or newer. We have run Cobertura on Windows XP and Linux (Fedora Core 4) using the 1.4.2 JDK. However, it should work on any platform and with any 1.3 or newer JDK. The Cobertura download packages include all the dependencies you’ll need (ASM, log4j, etc.)
What is code complexity and why should I care about it?
McCabe’s cyclomatic code complexity algorithm is used to determine how “complex” a given piece of code is. As code becomes more complex, it becomes more error prone. If a class has a high complexity number, then that class is a good target for additional test coverage.
When I generate coverage reports, why do they always show 100% coverage everywhere?
When I generate coverage reports, why do they always show 0% coverage everywhere?
Cobertura is probably using the wrong .ser file when generating the reports. When you instrument your classes, Cobertura generates a .ser file containing basic information about each class. As your tests run, Cobertura adds additional information to this same data file. If the instrumented classes can not find the data file when running then they will create a new one. It is important that you use the same cobertura.ser file when instrumenting, running, and generating reports.
The best way to do this is to specify the location of the data file when running your tests. You should pass the -Dnet.sourceforge.cobertura.datafile=${basedir}/cobertura.ser sysproperty to the JUnit task.
Another common problem is that the cobertura.ser file is deleted, but the previously instrumented classes are not also deleted. Any time you delete your coverage data file you should also deleted all instrumented classes.
Why is Cobertura causing me to have classpath conflicts with ASM?
Cobertura uses ASM to modify your bytecode. There are a few other popular programs that use ASM; Groovy and Hibernate, to name two. You could have problems if Cobertura uses a different version of asm and you add both versions to your classpath.
Cobertura only uses ASM when instrumenting. Cobertura does not need ASM in your classpath when running tests. If you’re seeing classpath conflicts, just make sure the asm jar that comes with Cobertura is used only by Cobertura, and only when instrumenting.
Is it possible to graphically show my test coverage over time?
Yes, using QALab. From their website, QALab “allows developers, architects and project managers alike to be presented with a trend of the QA statistics of their project.”
I have automated tests that use HttpUnit/HtmlUnit/Empirix/Rational Robot, can I use Cobertura?
Yes! The process is a bit more involved, but the concept is the same. First instrument your compiled classes. Then create your war file. Then deploy the war file into your application server (Tomcat, JBoss, WebLogic, WebSphere, etc). Now run your tests.
As your classes are accessed, they will create a “cobertura.ser” file on the disk. You may need to dig around a bit to find it. Cobertura puts this file in what it considers to be the current working directory. Typically this is the directory that the application server was started from (for example, C:\Tomcat\bin) Note: This file is not written to the disk until the application server exits. See below for how to work around this.
Now that you know where the cobertura.ser file is, you should modify your deploy step so that it moves the original cobertura.ser to the appropriate directory in your application server, and then moves it back when finished testing. Then run cobertura-report.
I’m using JBoss. When I stop the server, the coverage data file is not written. Or the coverage data file is 0 bytes. Or cobertura-report and cobertura-merge complain that the coverage data file is invalid (possibly throwing an EOFException).
Cobertura only writes the coverage data file at shutdown. It does this by adding a shutdown hook with Runtime.getRuntime().addShutdownHook(). JBoss has its own shutdown hook that calls System.halt() when its finished. If the JBoss shutdown hook finishes before the Cobertura shutdown hook, then the call to System.halt() causes the JVM to halt and the cobertura.ser file will be incomplete.
To fix this, set -Djboss.shutdown.forceHalt=false when starting JBoss.
Cobertura only writes the coverage data file when the application server shuts down. We do not want to stop our application server after running our tests.
It is possible to instruct Cobertura to write the data file. One of your classes should call the static method net.sourceforge.cobertura.coveragedata.ProjectData.saveGlobalProjectData(). For example, you could add something like this to a “logout” method in your web application:
try { String className = "net.sourceforge.cobertura.coveragedata.ProjectData"; String methodName = "saveGlobalProjectData"; Class saveClass = Class.forName(className); java.lang.reflect.Method saveMethod = saveClass.getDeclaredMethod(methodName, new Class[0]); saveMethod.invoke(null,new Object[0]); } catch (Throwable t) { }