【问题标题】:Best practice for looped JUnit test循环 JUnit 测试的最佳实践
【发布时间】:2018-12-03 15:38:35
【问题描述】:

在学校作业中,我应该为一个方法编写黑盒测试,该方法返回 true 的参数 false 否则。目前我的方法是

for (int i = 0; i < 80; i++) {
    assertTrue(someMethod(i));
}
for (int i = 80; i <= 100; i++) {
    assertFalse(someMethod(i));
}

但是,这需要 100 个单独的断言。是否有最佳/更好的实践方法?如果相关,我正在使用 JUnit 5,但如果需要可以切换到 JUnit 4(毕竟这只是一个学校作业)。问候。

【问题讨论】:

  • 循环不是正确的方法根本

标签: java unit-testing junit junit5 black-box-testing


【解决方案1】:

对于 JUnit 5,考虑重复测试功能:

https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests

对于您的情况,您可以重复 100 次:

@ParameterizedTest
@MethodSource("args")
public void so(int argument)
{
   assertTrue((argument < 80) == someMethod(argument));
}

private static IntStream args()
{
   return IntStream.range(0, 100);
}

我同意检查 1 - 100 不是完全必要的,只需检查 80 左右(79、80、81)。 可能唯一值得的情况是检查一个负数,但在这种情况下,即使这样也显得过分了。

如果您决定只检查 79,80,81,那么 ValueSource 注释更清晰:

@ParameterizedTest
@ValueSource(ints = { 79, 80, 81 })
public void so(int argument)
{
   assertTrue((argument < 80) == someMethod(argument));
}

【讨论】:

  • ParameterizedTest 是一个很好的工具。然而,测试中的逻辑并不是一个好主意。您建议在测试本身中复制被测代码的
【解决方案2】:

您通常只需测试边缘情况就可以了,也许还可以再测试一个范围之一的代表,例如

assertTrue(someMethod(79));
assertFalse(someMethod(80));

// not reaaaally necessary
assertTrue(someMethod(50));
assertFalse(someMethod(100));

在您的情况下,您可能还希望将截止值添加为常量(例如static final int THRESHOLD = 80)并在您的测试用例中使用它;这样,如果阈值发生变化,则更容易更改。

【讨论】:

    【解决方案3】:

    你可以做的(在 JUnit5 中)如下:

    编写(至少)三个测试用例,涵盖三个主要用例,即输入&lt; 80、输入&gt; 80 和输入= 80

    应该是这样的:

    @Test
    @DisplayName("[< 80]")
    @Tag("below_eighty")
    void numberBelowEightyTest(TestInfo testInfo) {
        int number = 79;
        assertTrue(someMethod(number));
    }
    
    @Test
    @DisplayName("[= 80]")
    @Tag("equals_eighty")
    void numberEqualsEightyTest(TestInfo testInfo) {
        int number = 80;
        assertFalse(someMethod(number));
    }
    
    @Test
    @DisplayName("[> 80]")
    @Tag("above_eighty")
    void numberAboveEightyTest(TestInfo testInfo) {
        int number = 81;
        assertFalse(someMethod(number));
    }
    

    在测试了这三个用例之后,由于直接测试了边界以及最近的邻居,您可以确定所有剩余的数字。

    【讨论】:

      【解决方案4】:

      如果有人使用 JUnit 4:

      @RunWith(Parameterized.class)
      public class PerformanceStatusTest {
      
          @Parameterized.Parameters
          public static List<Integer> data() {
              return IntStream.range(0, 100)
                      .boxed()
                      .collect(Collectors.toList());
          }
      
          private int testValue;
      
          public PerformanceStatusTest(final int testValue) {
              this.testValue = testValue;
          }
      
          @Test
          public void someMethodTest() {
              assertTrue((testValue < 80) == someMethod(testValue));
          }
      } 
      

      【讨论】:

        【解决方案5】:

        提到另一个选项,在这个简单的例子中,将进行全面检查:在 JUnit 5 平台上使用jqwik 进行基于属性的测试:

        import org.junit.jupiter.api.*;
        
        import net.jqwik.api.*;
        import net.jqwik.api.constraints.*;
        
        class PartitionedFunctionProperty {
        
            @Property
            void below80returnTrue(@ForAll @IntRange(min= 0, max = 79) int aNumber) {
                Assertions.assertTrue(someMethod(aNumber));
            }
        
            @Property
            void from80returnFalse(@ForAll @IntRange(min = 80, max = 100) int aNumber) {
                Assertions.assertFalse(someMethod(aNumber));
            }
        
            private boolean someMethod(int aNumber) {
                if (aNumber < 80) return true;
                return false;
            }
        }
        

        如果您想真正看到真正生成的完整范围,请添加 给属性方法注解@Report(Reporting.GENERATED),你会得到如下输出:

        timestamp = 2018-12-05T14:50:36.668, generated = [80]
        timestamp = 2018-12-05T14:50:36.671, generated = [81]
        timestamp = 2018-12-05T14:50:36.672, generated = [82]
        timestamp = 2018-12-05T14:50:36.672, generated = [83]
        ...
        timestamp = 2018-12-05T14:50:36.676, generated = [98]
        timestamp = 2018-12-05T14:50:36.676, generated = [99]
        timestamp = 2018-12-05T14:50:36.677, generated = [100]
        
        timestamp = 2018-12-05T14:50:36.679
            tries = 21
            checks = 21
            generation-mode = EXHAUSTIVE
            after-failure = SAMPLE_ONLY
            seed = 4490524914178941008
        

        找到full working example on github

        【讨论】:

          猜你喜欢
          • 2010-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-29
          • 2020-02-05
          • 2011-06-11
          • 2018-09-23
          相关资源
          最近更新 更多