Using Coverage Contexts

Still need help?

The Atlassian Community is here for you.

Ask the community

Clover defines a Context as a part of source code that matches a specified structure or pattern. Contexts are either pre-defined or user-defined at instrumentation time. Each context must have a unique name. At report time, you can specify which contexts you would like to exclude in the coverage report.

 

Block Contexts

Block Contexts are pre-defined by Clover. They represent 'block' syntactic constructs in the Java language. A full list of supported Block Contexts is shown below.

Clover's block context feature currently does not support Groovy.

Name

Description

static

Static initializer block

instance

Instance initializer block

constructor

Constructor body

method

Method body

switch

Switch statement body

while

While loop body

do

do-while loop body

for

For loop body

if

if body

else

else body

try

try body

catch

catch body

finally

finally body

sync

synchronized block

assert

assert statement

@deprecated

a deprecated block

Method Contexts

A Method Context represents the set of methods whose signature matches a given pattern. Clover provides several pre-defined method contexts:

Name

Regexp

Description

private

(.* )?private .*

matches all private methods

property

(.* )?public .*(get|set|is)[A-Z0-9].*

matches all property getters/setters

A method signature includes all annotations, modifiers (public, static, final etc), the return type, the method name, parameter types and names, the throws clause and exceptions.

Note

When matching method signatures against context regexps, whitespace is normalized and comments are ignored.

You can define your own method contexts via the <methodContext> sub-element of <clover-setup>, or via the configuration panel of your Clover IDE Plugin.

Note

Contexts are matched against your source at instrumentation-time. This means you need to re-instrument your code after defining a new context.

Method Contexts with Groovy code

While Groovy syntax is flexible in nature, the regular expressions defined in the regexp parameters of <methodContext> elements must match a 'normalized' method signature.

Bear in mind that this is not necessarily how you would define the method in your Groovy source code.

For example, in Groovy code, a method defined via the 'def' keyword is always 'public'. This means that your regexp must actually match "public def". Hence, if you wanted to create a regexp that matched the following Groovy method:

def void foo()

Your regexp must assume a match against:

public def void foo()

Normalized method signature rules for defining regexp parameters:

The following list illustrates the normalized form of the method signature (and hence, order) in which your regexp must be defined to match specific methods in your Groovy source code:

  1. Modifiers– in the following order:
    1. public
    2. protected
    3. private
    4. abstract
    5. static
    6. final
    7. transient
    8. volatile
    9. synchronized
    10. native
    11. strictfp
    12. interface
      (Refer to Sun Java's documentation for more information.)
  2. Type Parameters (optional) – for example, <T>, <E extends Object>
  3. Return Type – for example, void, int, String, Object[]
  4. Name – for example, myMethod
  5. Parameter List – for example, (String arg1, int arg2)
  6. Throws – for example, throws Exception1, Exception2

 

Examples of normalized signatures for Groovy

// normalized signature is: "private void <init>()"
private PrivateConstructor() {
        
}

// normalized signature is: "public void <init>(int i)"
public PublicConstructor(int i) {

}
    
// normalized signature is: "private def implicitVoidMethod()"
private implicitVoidMethod() {

}
    
// normalized signature is: "private void explicitVoidMethod()"
private void explicitVoidMethod() { 

}
    
// normalized signature is: "private int someNonVoidMethod()"
private int someNonVoidMethod() {
    return 0
} 

// normalized signature is: "public static synchronized Object[] complexSignature(String i, List<Integer> j)"
synchronized static public Object [ ]    complexSignature(   String i, List < Integer > j) {
    return new Object[0]    
}

 

Statement Contexts

Clover's statement context feature currently does not support Groovy.

A Statement Context represents the set of statements that match a given pattern. For example, you might want to set up a statement context to allow you to filter out 'noisy' statements (such as logging calls) by defining a statement context regexp LOG\.debug.*.

A regular expression defined in a statement context will be matched against a normalized form of the statement:

  • any white space characters before and after the statement are removed
  • any newline characters are removed
  • single space character is used to separate code tokens

When writing a regular expression you should take into account that in case of nested statements, the outer statement will contain inner statements as well. Consider the following example:

void testStatementContext() {	
    while (true) {
        if (logger.isDebugEnabled()) {
            logger.debug("abc");			
        }
    }		
}

in this case, method body has three statements:

a) the while loop

while (true) {{ if (logger.isDebugEnabled()) {{ logger.debug("abc"); } }}

b) the if condition

if (logger.isDebugEnabled()) {{ logger.debug("abc"); }

c) the logger.debug() method call

logger.debug("abc");

 

Assuming that you'd like to filter-out "logger.debug" calls, the regular expression should look like this:

<statementcontext name="logger" regexp="^logger\.debug.*"/>

Note that if the expression would be written as "^.*logger\.debug.*", then it would match also outer statements.

Using Context Filters

Note

This section describes using context filters with Ant. For details of using filters with the IDE plugins, see the individual documentation for the plugin.

Filtering catch blocks

In some cases you may not be interested in the coverage of statements inside catch blocks. To filter them, you can use Clover's predefined catch context to exclude statements inside catch blocks from a coverage report:

<clover-report>
       <current outfile="clover_html">
         <format type="html" filter="catch"/>
       </current>
   </clover-report>

This generates a source-level HTML report that excludes coverage from statements inside catch blocks.

Filtering simple methods

In order to filter-out simple getters and setters you can use built-in "property" method context. 

You can define also own filter, based on cyclomatic complexity and/or number of statements. For example:

<clover-setup ...>
    <!-- Don't instrument methods which have cyclomatic complexity <= 1 or <= 3 statements -->
    <methodContext name="simple_method" regexp=".*" maxComplexity="1" maxStatements="3"/>
</clover-setup>

 

Filtering logging statements

To remove logging statements for coverage reports, you will need to define one or more statement contexts that match logging statements in your source:

<clover-setup ...>
    <statementContext name="log" regexp="^LOG\..*"/>
    <statementContext name="iflog" regexp="^if \(LOG\.is.*"/>
    <methodContext name="main" regexp="public static void main\(String args\[\]\).*"/>
    ...
</clover-setup>

This defines two statement contexts and one method context. The first matches statements that start with 'LOG.' while the second matches statements that start with  'if (LOG.', which is designed to match conditional logging statements such as:

if (LOG.isDebugEnabled()) {
    // do some expensive debug logging
}

The third matches all 'main' methods that have a String Array named 'args' in the constructor:

public static void main(String args[]) throws Exception

After defining these contexts, you now need to re-compile with Clover and then re-run your tests. You can then generate a report that excludes logging statements:

<clover-report>
    <current outfile="clover_html" title="My Coverage">
        <format type="html" filter="log,iflog"/>
    </current>
</clover-report>

This generates a source-level HTML report that excludes coverage from logging statements.

Last modified on Jan 14, 2017

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.