【问题标题】:How to test all combinations of bad parameters?如何测试不良参数的所有组合?
【发布时间】:2016-06-01 11:33:54
【问题描述】:

让我们假设一个简单的方法抛出一个IndexOutOfBoundsException 对于无效的索引对(二维数组)。

我将如何测试是否会针对所有错误组合引发异常 指数?

(当然,如果 一次调用引发异常)

@Test(expected = Exception.class)
public void validateIndices(){
    check(0,-1);
    check(-1,0);
    check(0,COLS + 1);
    check(ROWS + 1, 0);
}

有没有通用的测试方法 方法的参数变化?

【问题讨论】:

  • 就像大多数关于单元测试的基本教程一样:每个测试方法测试一个条件。因此,您的四个check 呼叫至少需要四个。
  • @Tom 重复四次会不会很重复?
  • “重复四次会不会很重复?” 那又怎样?由你决定。要么你想要一个失败的 validateIndices 方法,你必须手动检查这些调用中的哪一个失败,你有像 testCheck_invalidSecondArgument 这样的专用方法,所以要看看哪个失败了。
  • @Jam 我希望您的 check 方法实际上并没有抛出 Exception: expect 最具体的异常,否则您捕获的异常可能与您的想法完全无关你正在测试。

标签: java exception junit


【解决方案1】:

除了@Nicolas_Filotto 回答,还可以使用Junit Theories。它更具可读性,并且与 Parameterized 不同,它将使用所有可能的参数组合执行测试。

@RunWith(Theories.class)
public class MyTest {
    @DataPoints("cols")
    public static int[] rowValues(){
        return new int[]{0, -1, 1, 2};
    }
    @DataPoints("rows")
    public static int[] colValues(){
        return new int[]{0, -1, 4, 5};
    }

    @Theory
    public void upperBoundIsChecked(@FromDataPoints("cols") int col,
                                    @FromDataPoints("rows") int row){
        assumeTrue(row >= ROWS || col >= COLS);
        try {
            check(col, row);
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException ignore){}
    }

    @Theory
    public void lowerBoundIsChecked(@FromDataPoints("cols") int col,
                                    @FromDataPoints("rows") int row){
        assumeTrue(row < 0 || col < 0);
        try {
            check(col, row);
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException ignore){}
    }

    @Theory
    public void validIndicesNoException(@FromDataPoints("cols") int col,
                                        @FromDataPoints("rows") int row){
        assumeTrue(row >= 0 && col >= 0 && row < ROWS && col < COLS);
        try {
            check(col, row);
        } catch (Exception e){
            fail("Should not have thrown an exception: " + e.getMessage());
        }
    }

}

每个理论都会检查与理论假设相匹配的行和列的所有可能组合。

或者,如果您的列和行列表相同,则可以更轻松地完成:

@RunWith(Theories.class)
public class MyTest {

   @DataPoints
   public static int[] values(){
      return new int[]{0, -1};
   }
   @Theory
   public void validateIndices(int col, int row){
      check(col,row);
   }
}

【讨论】:

  • 理论对于测试数据点组合的广泛行为非常有用。未提及的一个好处是,如果理论失败,junit 结果将显示导致理论失败的特定值组合。
【解决方案2】:

在你的情况下,我会Parameterized我的单元测试来测试所有组合与相同的测试更多信息here

在你的情况下,它看起来像这样:

@RunWith(Parameterized.class)
public class MyTest {
    @Parameterized.Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
            { 0, -1 }, { -1, 0 }
        });
    }

    @Parameterized.Parameter
    public int row;

    @Parameterized.Parameter(value = 1)
    public int col;

    @Test(expected = IndexOutOfBoundsException.class)
    public void validateIndices(){
        check(row, col);
    }
}

【讨论】:

    【解决方案3】:

    其他答案当然是正确的,从某种意义上说,它们可以满足您的需求,但是它们在概念上有一个很大的缺点:它们只能检查错误情况……您必须手动 指定。

    意思:这种测试只证明你的“被测代码”对那些定义明确的案例做了预期的事情。

    将其与您将告诉环境的编程模型进行比较:“这就是我期望我的函数的行为方式”;然后那个环境试图找到你的函数中断的输入。

    如果你觉得这很有趣,你应该看看QuickCheck。虽然不是真正的“原生”Java,而且目前绝对不是“主流”......它可能值得一试。

    【讨论】:

      【解决方案4】:

      好吧,如果索引都是 Integer 值,那么带有 try-catch 语句的 for 循环是可能的:

      for (int i = iBegin; i < iEnd; i++) {
        for (int j = jBegin; j < jEnd; j++) {
          try { check(i, j); }
          catch (Exception e) { iList.add(i); jList.add(j); }
        }
      }
      

      (在这种情况下,iList 和 jList 是某种类型的 Collection;iBegin、jBegin、iEnd 和 jEnd 是整数值,它们给出了变化的界限)

      【讨论】:

        猜你喜欢
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-06
        • 2021-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多