Skip to content

Commit

Permalink
Properly report skipped iterations (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
rtretyak committed May 28, 2020
1 parent 391283c commit aa38b04
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import com.athaydes.spockframework.report.internal.SpecProblem
import com.athaydes.spockframework.report.internal.SpockReportsConfiguration
import com.athaydes.spockframework.report.util.Utils
import groovy.util.logging.Slf4j
import org.junit.AssumptionViolatedException
import org.spockframework.runtime.IRunListener
import org.spockframework.runtime.extension.IGlobalExtension
import org.spockframework.runtime.extension.IMethodInterceptor
import org.spockframework.runtime.extension.IMethodInvocation
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.IterationInfo
Expand Down Expand Up @@ -75,7 +78,21 @@ class SpockReportExtension implements IGlobalExtension {
@Override
void visitSpec( SpecInfo specInfo ) {
if ( reportCreator != null ) {
specInfo.addListener createListener()
def listener = createListener()
specInfo.addListener listener
specInfo.allFeatures*.getFeatureMethod()*.addInterceptor(new IMethodInterceptor() {
@Override
void intercept( IMethodInvocation invocation ) throws Throwable {
try {
invocation.proceed()
} catch( Throwable t ) {
if( t in AssumptionViolatedException ) {
listener.error new ErrorInfo( invocation.method, t )
}
throw t
}
}
})
} else {
log.warn "Not creating report for ${ specInfo.name } as reportCreator is null"
}
Expand Down Expand Up @@ -271,5 +288,4 @@ class SpecInfoListener implements IRunListener {
private static FeatureInfo dummyFeature() {
new FeatureInfo( name: '<No Feature initialized!>' )
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class HtmlReportCreator extends AbstractHtmlCreator<SpecData>
final String name = Utils.featureNameFrom( feature, iteration, index )
final cssClass = problems.any( Utils.&isError ) ? 'error' :
problems.any( Utils.&isFailure ) ? 'failure' :
Utils.isSkipped( feature ) ? 'ignored' : 'pass'
problems.any( Utils.&isSkipped ) ? 'ignored' : 'pass'
li {
a( href: "#${name.hashCode()}", 'class': "feature-toc-$cssClass", name )
}
Expand Down Expand Up @@ -249,7 +249,7 @@ class HtmlReportCreator extends AbstractHtmlCreator<SpecData>
String name = Utils.featureNameFrom( feature, iteration, index )
final cssClass = problems.any( Utils.&isError ) ? 'error' :
problems.any( Utils.&isFailure ) ? 'failure' :
Utils.isSkipped( feature ) ? 'ignored' : ''
problems.any( Utils.&isSkipped ) ? 'ignored' : ''
writeFeatureDescription( builder, name, cssClass,
featureAnnotation( feature, Ignore ),
featureAnnotation( feature, PendingFeature ),
Expand Down Expand Up @@ -490,7 +490,7 @@ class HtmlReportCreator extends AbstractHtmlCreator<SpecData>

private void writeIteration( MarkupBuilder builder, IterationInfo iteration,
List<SpecProblem> errors ) {
builder.tr( 'class': errors ? 'ex-fail' : 'ex-pass' ) {
builder.tr( 'class': errors.any( Utils.&isSkipped ) ? 'ex-skip' : errors ? 'ex-fail' : 'ex-pass' ) {
for ( value in iteration.dataValues ) {
def writableValue = value instanceof Runnable ?
"<executable>" :
Expand All @@ -502,7 +502,15 @@ class HtmlReportCreator extends AbstractHtmlCreator<SpecData>
}

private static String iterationResult( List<SpecProblem> errors ) {
errors ? 'FAIL' : 'OK'
if( errors.any { Utils.isFailure(it) } ) {
'FAIL'
} else if( errors.any { Utils.isError(it) } ) {
'ERROR'
} else if( errors.any { Utils.isSkipped(it) } ) {
'SKIP'
} else {
'OK'
}
}

private void writeFeatureDescription( MarkupBuilder builder, String name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,18 @@ class ProblemBlockWriter {

void writeProblemBlockForIteration( MarkupBuilder builder, IterationInfo iteration,
List<SpecProblem> problems, Long time ) {
if ( problems ) {
def failures = problems.findAll { Utils.isError(it) || Utils.isFailure(it) }
def skips = problems.findAll( Utils.&isSkipped )
if ( failures ) {
problemsContainer( builder ) {
def problemsByIteration = problemsByIteration( [ ( iteration ): problems ], [ ( iteration ): time ] )
def problemsByIteration = problemsByIteration( [ ( iteration ): failures ], [ ( iteration ): time ] )
problemsByIteration.each { it.dataValues = null } // do not show data values in the report
writeProblems( builder, problemsByIteration )
}
}
if ( skips ) {
skipsContainer( builder ) {
def problemsByIteration = problemsByIteration( [ ( iteration ): skips ], [ ( iteration ): time ] )
problemsByIteration.each { it.dataValues = null } // do not show data values in the report
writeProblems( builder, problemsByIteration )
}
Expand All @@ -45,6 +54,19 @@ class ProblemBlockWriter {
}
}

void skipsContainer( MarkupBuilder builder, Runnable createProblemList ) {
builder.tr {
td( colspan: '10' ) {
div( 'class': 'skip-description' ) {
div( 'class': 'skip-header', 'Skip reason:' )
div( 'class': 'problem-list' ) {
createProblemList.run()
}
}
}
}
}

private void writeProblems( MarkupBuilder builder, List<Map> problems ) {
problems.each { Map problem ->
if ( !problem.messages ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.athaydes.spockframework.report.internal

import org.junit.ComparisonFailure
import org.junit.internal.AssumptionViolatedException
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.IterationInfo
Expand Down Expand Up @@ -41,11 +42,18 @@ class SpecProblem {
}

FailureKind getKind() {
failure.exception instanceof AssertionError || failure.exception instanceof ComparisonFailure ?
FailureKind.FAILURE :
switch(failure.exception) {
case AssertionError || ComparisonFailure:
FailureKind.FAILURE
break
case AssumptionViolatedException:
FailureKind.ASSUMPTION_FAILURE
break
default:
FailureKind.ERROR
}

}
}
}

/**
Expand All @@ -54,5 +62,5 @@ class SpecProblem {
* An ERROR means an unexpected {@link Throwable} was thrown, while FAILURE means a test assertion failure.
*/
enum FailureKind {
FAILURE, ERROR
FAILURE, ASSUMPTION_FAILURE, ERROR
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Utils {
static Map stats( SpecData data ) {
def failures = countProblems( data.featureRuns, this.&isFailure )
def errors = countProblems( data.featureRuns, this.&isError )
def skipped = data.info.allFeaturesInExecutionOrder.count { FeatureInfo f -> isSkipped( f ) }
def skipped = countProblems( data.featureRuns, this.&isSkipped )
def total = data.info.allFeatures.size()
def totalExecuted = countFeatures( data.featureRuns ) { FeatureRun run -> !isSkipped( run.feature ) }
def successRate = successRate( totalExecuted, ( errors + failures ).toInteger() )
Expand Down Expand Up @@ -101,6 +101,10 @@ class Utils {
problem.kind == FailureKind.ERROR
}

static boolean isSkipped( SpecProblem problem ) {
problem.kind == FailureKind.ASSUMPTION_FAILURE
}

static boolean isSkipped( FeatureInfo featureInfo ) {
// pending features are not marked as skipped but they are always skipped or fail
featureInfo.skipped || featureAnnotation( featureInfo, PendingFeature ) != null
Expand Down
16 changes: 16 additions & 0 deletions src/main/resources/spock-feature-report.css
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,22 @@ div.problem-description {
border-radius: 10px;
}

div.skip-description {
padding: 10px;
background: lightgray;
border-radius: 10px;
}

div.problem-header {
font-weight: bold;
color: red;
}

div.skip-header {
font-weight: bold;
color: grey;
}

div.problem-list {

}
Expand Down Expand Up @@ -197,6 +208,11 @@ td.ex-result {
font-weight: bold;
}

.ex-skip {
color: grey;
font-weight: bold;
}

div.block-kind {
margin: 2px;
font-style: italic;
Expand Down

0 comments on commit aa38b04

Please sign in to comment.