-1

我想定义一个抽象基类,它定义了我想在测试各种 API 时一遍又一遍地实现的通用可重用测试用例。这个想法是定义一次测试,然后我可以从通用测试继承以获得测试定义,而我的测试代码所要做的就是实现如何执行测试的细节。这样我就不会错过好的测试用例,当我想出另一个好的测试用例来测试时,我不必重新发明轮子,也不必在几十个地方进行更改。

本质上,我正在做参数化测试,其中参数是在基类中定义的。预期结果也在基类中定义。但是,有时需要覆盖预期结果。例如,一个普通的字符串字段可能允许任何字符,而一个对象名称字段可能(或在我的情况下)限制哪些字符是合法的。例如,字符串字段允许“?” 在值中,名称字段没有。

我试图找出一种在基类中定义参数 ONCE 的干净方法,并且只定义一次预期结果,但可以选择在上下文需要的实现类中覆盖它。

我遇到的问题是,当您覆盖一个方法时,您必须替换它的实现。你不能只替换它的一部分。我想在不覆盖参数部分的情况下替换预期结果。我也不认为将每个测试分成两种方法是一种干净或理想的解决方案,一种提供参数,另一种定义预期行为。

我正在考虑的一种选择是使用注释来定义预期结果。然后我可以覆盖注解,然后将实现委托给基类实现。只要基类使用注释来决定如何表现,它就应该起作用。

例如:(在伪代码中,不是真正的 Java)

abstract class foo {

  @fubar(true)
  void test1() { doSomething( param1 ) }

  @fubar(true)
  void test2() { doSomething( param2 ) }

  @fubar(false)
  void test3() { doSomething( param3 ) }

  boolean isFubar( void ) { ... }  // generic annotation grabber

  void doSomething( p ) {
    if ( isFubar() ) 
      doThis( p ) 
    else 
      doThat( p );
  }

  // abstract methods to be defined in the implementing class
  void doThis( p );
  void doThat( p );
}

class bar extends foo {

  // change the expected result for test2 only
  @fubar(false)
  void test2() { super.test2(); }

  // define how to execute the tests
  void doThis(p) { ... }
  void doThat(p) { ... }

}

class baz extends bar {

  // only changes the semantics of test3, nothing else
  @fubar(true)
  void test3() { super.test3() }

}

鉴于这种层次结构,foo.test1()bar.test1()baz.test1()都做完全相同的事情。而foo.test2()做一件事,又做另一bar.test2()件事baz.test2()。同样,foo.test3()bar.test3()一件事,却baz.test3()会有所不同。

我可以使用注释来完成此行为吗?如果是这样,isFubar会是什么样子?我还没有看到方法名称未知的这种反射的示例。

作为旁注,如果有一种更清洁的方法来完成预期的行为,我很乐意听到它是什么。

4

1 回答 1

0

要在调用堆栈中找到最早匹配的注解,可以使用如下函数:

static <T extends Annotation> T seekAnnotation(Class<T> annotationClass) {
    T annotation = null;
    try {
        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
            T found = seekAnnotation(annotationClass, ste);
            if (found != null) {
                annotation = found;
            }
        }
    } catch (Exception e) {
        //
    }
    return annotation;
}

static <T extends Annotation> T seekAnnotation(Class<T> annotationClass, StackTraceElement ste) {
    T annotation = null;
    try {
        Class<?> claz = Class.forName(ste.getClassName());
        Method method = claz.getDeclaredMethod(ste.getMethodName());
        annotation = method.getAnnotation(annotationClass);
    } catch (Exception e) {
        //
    }
    return annotation;
}

有更多的工作使它变得健壮,但这将是基本的想法。所以你的方法isFubar()看起来像

boolean isFubar() {
    return seekAnnotation(fubar.class).value();
}
于 2017-07-26T01:02:42.040 回答