当前位置:  开发笔记 > 编程语言 > 正文

更改参数化测试的名称

如何解决《更改参数化测试的名称》经验,为你挑选了6个好方法。

在JUnit4中使用参数化测试时,有没有办法设置我自己的自定义测试用例名称?

我想将默认值 - 更改为[Test class].runTest[n]有意义的内容.



1> rescdsk..:

此功能已进入JUnit 4.11.

要使用更改参数化测试的名称,您可以说:

@Parameters(name="namestring")

namestring 是一个字符串,可以有以下特殊占位符:

{index} - 这组参数的索引.默认namestring{index}.

{0} - 来自此测试调用的第一个参数值.

{1} - 第二个参数值

等等

测试的最终名称将是测试方法的名称,后面是namestring括号,如下所示.

例如(改编自Parameterized注释的单元测试):

@RunWith(Parameterized.class)
static public class FibonacciTest {

    @Parameters( name = "{index}: fib({0})={1}" )
    public static Iterable data() {
        return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
                { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
    }

    private final int fInput;
    private final int fExpected;

    public FibonacciTest(int input, int expected) {
        fInput= input;
        fExpected= expected;
    }

    @Test
    public void testFib() {
        assertEquals(fExpected, fib(fInput));
    }

    private int fib(int x) {
        // TODO: actually calculate Fibonacci numbers
        return 0;
    }
}

会给出像testFib[1: fib(1)=1]和的名字testFib[4: fib(4)=3].(testFib名称的一部分是方法名称@Test).


很好,但是如果`{0}`和`{1}`是数组呢?理想情况下,JUnit应该调用`Arrays.toString({0})`,而不是`{0} .toString()`.例如,我的`data()`方法返回`Arrays.asList(new Object [] [] {{new int [] {1,3,2},new int [] {1,2,3}}}}) ;`.
没有理由它不会在4.11中,它在掌握中.现在当4.11可用时,这是一个很好的问题:-)
是的,但有一个错误.如果在参数"name"中放置一个括号,就像在此发布中那样,它会破坏Eclipse中单元测试名称的显示.

2> Yishai..:

看看JUnit 4.5,它的运行者显然不支持它,因为该逻辑被隐藏在Parameterized类中的私有类中.您无法使用JUnit参数化运行器,而是创建自己的运行器,这将理解名称的概念(这导致您可能如何设置名称的问题......).

从JUnit的角度来看,如果不是(或除了)只是传递一个增量,它们会传递逗号分隔的参数.TestNG就是这么做的.如果该功能对您很重要,您可以在www.junit.org上引用的yahoo邮件列表上发表评论.


刚刚检查过,有一个突出的功能请求:http://github.com/KentBeck/junit/issues#issue/44请投票.
@Frank,我认为解决此问题的版本尚未发布.它将在JUnit 4.11中.那时(假设设计保持不变),它将以文本方式指定您如何命名测试,包括将参数作为名称.实际上非常好.
以下是原始问题的更新链接https://github.com/junit-team/junit/issues/44以供将来参考
JUnit 4.11现已发布:-)
如果JUnit中有这方面的改进,我将非常感谢!

3> darrenp..:

我最近在使用JUnit 4.3.1时遇到了同样的问题.我实现了一个扩展Parameterized的新类,名为LabelledParameterized.它已使用JUnit 4.3.1,4.4和4.5进行了测试.它使用@Parameters方法中每个参数数组的第一个参数的String表示来重构Description实例.您可以在以下位置查看此代码:

http://code.google.com/p/migen/source/browse/trunk/java/src/.../LabelledParameterized.java?r=3789

以及它在以下地方使用的一个例子:

http://code.google.com/p/migen/source/browse/trunk/java/src/.../ServerBuilderTest.java?r=3789

测试描述在Eclipse中很好地格式化,这是我想要的,因为这使得失败的测试更容易找到!我可能会在接下来的几天/几周内进一步完善和记录课程.放下'?' 如果你想要最前沿的URL的一部分.:-)

要使用它,您所要做的就是复制该类(GPL v3),并将@RunWith(Parameterized.class)更改为@RunWith(LabelledParameterized.class),假设参数列表的第一个元素是一个合理的标签.

我不知道JUnit的任何后续版本是否解决了这个问题,但即使他们这样做了,我也无法更新JUnit,因为我的所有联合开发人员也必须更新,我们的优先级高于重新加工.因此,类中的工作可以由多个版本的JUnit进行编译.


注意:有一些反射jiggery-pokery,因此它运行在上面列出的不同JUnit版本.可以在此处找到专门针对JUnit 4.3.1的版本,对于JUnit 4.4和4.5,可以在此处找到.



4> David Moles..:

随着Parameterized作为一种模式,我写我自己的自定义测试跑步/套件-只花了约半小时.它与darrenp略有不同LabelledParameterized,因为它允许您明确指定名称而不是依赖于第一个参数toString().

它也不使用数组,因为我讨厌数组.:)

public class PolySuite extends Suite {

  // //////////////////////////////
  // Public helper interfaces

  /**
   * Annotation for a method which returns a {@link Configuration}
   * to be injected into the test class constructor
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  public static @interface Config {
  }

  public static interface Configuration {
    int size();
    Object getTestValue(int index);
    String getTestName(int index);
  }

  // //////////////////////////////
  // Fields

  private final List runners;

  // //////////////////////////////
  // Constructor

  /**
   * Only called reflectively. Do not use programmatically.
   * @param c the test class
   * @throws Throwable if something bad happens
   */
  public PolySuite(Class c) throws Throwable {
    super(c, Collections.emptyList());
    TestClass testClass = getTestClass();
    Class jTestClass = testClass.getJavaClass();
    Configuration configuration = getConfiguration(testClass);
    List runners = new ArrayList();
    for (int i = 0, size = configuration.size(); i < size; i++) {
      SingleRunner runner = new SingleRunner(jTestClass, configuration.getTestValue(i), configuration.getTestName(i));
      runners.add(runner);
    }
    this.runners = runners;
  }

  // //////////////////////////////
  // Overrides

  @Override
  protected List getChildren() {
    return runners;
  }

  // //////////////////////////////
  // Private

  private Configuration getConfiguration(TestClass testClass) throws Throwable {
    return (Configuration) getConfigMethod(testClass).invokeExplosively(null);
  }

  private FrameworkMethod getConfigMethod(TestClass testClass) {
    List methods = testClass.getAnnotatedMethods(Config.class);
    if (methods.isEmpty()) {
      throw new IllegalStateException("@" + Config.class.getSimpleName() + " method not found");
    }
    if (methods.size() > 1) {
      throw new IllegalStateException("Too many @" + Config.class.getSimpleName() + " methods");
    }
    FrameworkMethod method = methods.get(0);
    int modifiers = method.getMethod().getModifiers();
    if (!(Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
      throw new IllegalStateException("@" + Config.class.getSimpleName() + " method \"" + method.getName() + "\" must be public static");
    }
    return method;
  }

  // //////////////////////////////
  // Helper classes

  private static class SingleRunner extends BlockJUnit4ClassRunner {

    private final Object testVal;
    private final String testName;

    SingleRunner(Class testClass, Object testVal, String testName) throws InitializationError {
      super(testClass);
      this.testVal = testVal;
      this.testName = testName;
    }

    @Override
    protected Object createTest() throws Exception {
      return getTestClass().getOnlyConstructor().newInstance(testVal);
    }

    @Override
    protected String getName() {
      return testName;
    }

    @Override
    protected String testName(FrameworkMethod method) {
      return testName + ": " + method.getName();
    }

    @Override
    protected void validateConstructor(List errors) {
      validateOnlyOneConstructor(errors);
    }

    @Override
    protected Statement classBlock(RunNotifier notifier) {
      return childrenInvoker(notifier);
    }
  }
}

一个例子:

@RunWith(PolySuite.class)
public class PolySuiteExample {

  // //////////////////////////////
  // Fixture

  @Config
  public static Configuration getConfig() {
    return new Configuration() {
      @Override
      public int size() {
        return 10;
      }

      @Override
      public Integer getTestValue(int index) {
        return index * 2;
      }

      @Override
      public String getTestName(int index) {
        return "test" + index;
      }
    };
  }

  // //////////////////////////////
  // Fields

  private final int testVal;

  // //////////////////////////////
  // Constructor

  public PolySuiteExample(int testVal) {
    this.testVal = testVal;
  }

  // //////////////////////////////
  // Test

  @Ignore
  @Test
  public void odd() {
    assertFalse(testVal % 2 == 0);
  }

  @Test
  public void even() {
    assertTrue(testVal % 2 == 0);
  }

}



5> 小智..:

从junit4.8.2开始,您只需复制Parameterized类即可创建自己的MyParameterized类.更改TestClassRunnerForParameters中的getName()和testName()方法.



6> dsaff..:

您可能还想尝试JUnitParams:http://code.google.com/p/junitparams/

推荐阅读
手机用户2402852387
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有