如何使用注释扩展使spock在运行时执行不同的方法?

时间:2015-03-27 23:56:57

标签: java reflection groovy spock

首先,如果有一种更简单的方法来解决这个问题,这里是我想要完成的概述。我想使用KnownIssue注释(扩展AbstractAnnotationDrivenExtension)来注释我的测试方法,该注释将缺陷ID作为参数并在执行测试之前检查缺陷的状态。如果缺陷是固定的,它将继续执行,如果它没有修复我希望它忽略测试,但如果它被关闭或删除,我想引发测试失败,记录说应该删除或更新测试自从现在关闭或删除缺陷后删除了注释。

我一直在努力,直到导致测试失败。我尝试过的东西不起作用:

  • 在visitFeatureAnnotation方法中抛出异常,导致失败,导致之后的所有测试都不执行。
  • 创建一个扩展Spec的类,并包含一个记录消息并失败的测试方法,然后尝试使用feature.featureMethod.setReflection()将方法设置为执行另一个方法。在这种情况下,我得到一个java.lang.IllegalArgumentException:object不是声明类的实例
  • 然后我尝试使用ExpandoMetaClass将方法直接添加到declaringClass,并指向feature.featureMethod.setReflection指向它,但我仍然得到相同的IllegalArgumentException。

以下是我在visitFeatureAnnotation方法中的最新尝试内容:

def myMetaClass = feature.getFeatureMethod().getReflection().declaringClass.metaClass
myMetaClass.KnownIssueMethod = { -> return false }
feature.featureMethod.setReflection(myMetaClass.methods[0].getDoCall().getCachedMethod());

关于如何实现这一点的任何其他想法,或者导致测试失败,或者用另一个失败的方法替换该方法?

1 个答案:

答案 0 :(得分:1)

好的......我终于想出了一个解决方案。这就是我的工作。在visitFeatureAnnotation方法中,我添加了一个我创建的CauseFailureInterceptor。

如果有人感兴趣,这里是完整的源代码,只需要你扩展KnownIssueExtension并实现抽象方法getDefectStatus:

public abstract class KnownIssueExtension extends AbstractAnnotationDrivenExtension<KnownIssue> {
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(KnownIssueExtension.class)
    public void visitFeatureAnnotation(KnownIssue knownIssue, FeatureInfo feature) {
        DefectStatus status = null
        try{
            status = getDefectStatus(knownIssue.value())
        } catch(Exception ex){
            LOGGER.warn("Unable to determine defect status for defect ID '{}', test case {}", knownIssue.value(), feature.getName())
            // If we can't get info from Defect repository, just skip it, it should not cause failures or cause us not to execute tests.
        }
        if (status != null){
            if(!status.open && !status.fixed){
                LOGGER.error("Defect with ID '{}' and title '{}' is no longer in an open status and is not fixed, for test case '{}'.  Update or remove test case.", knownIssue.value(), status.defectTitle, feature.getName())
                feature.addInterceptor(new CauseFailureInterceptor("Defect with ID '" + knownIssue.value() + "' and title '" + status.defectTitle + "' is no longer in an open status and is not fixed, for test case '" + feature.getName() + "'.  Update or remove test case."))
            }else if (status.open && !status.fixed){
                LOGGER.warn("Defect with ID '{}' and title '{}' is still open and has not been fixed.  Not executing test '{}'", knownIssue.value(), status.defectTitle, feature.getName())
                feature.setSkipped(true)
            }else if (!status.open && status.fixed){
                LOGGER.error("Defect with ID '{}' and title '{}' has been fixed and closed.  Remove KnownIssue annotation from test '{}'.", knownIssue.value(), status.defectTitle, feature.getName())
                feature.addInterceptor(new CauseFailureInterceptor("Defect with ID '" + knownIssue.value() + "' and title '" + status.defectTitle + "' has been fixed and closed.  Remove KnownIssue annotation from test '" + feature.getName() + "'."))
            }else { // status.open && status.fixed
                LOGGER.warn("Defect with ID '{}' and title '{}' has recently been fixed.  Remove KnownIssue annotation from test '{}'", knownIssue.value(), status.defectTitle, feature.getName())
            }
        }
    }

    public abstract DefectStatus getDefectStatus(String defectId)

}

public class CauseFailureInterceptor extends AbstractMethodInterceptor{
    public String failureReason
    public CauseFailureInterceptor(String failureReason = ""){
        this.failureReason = failureReason
    }

    @Override
    public void interceptFeatureExecution(IMethodInvocation invocation) throws Throwable {
        throw new Exception(failureReason)
    }
}

class DefectStatus{
    boolean open
    boolean fixed
    String defectTitle
}