【问题标题】:JUnit4 fail() is here, but where is pass()?JUnit4 fail() 在这里,但是 pass() 在哪里?
【发布时间】:2018-12-20 19:21:31
【问题描述】:

JUnit4 库中有一个fail() 方法。我喜欢它,但是缺少库中不存在的pass() 方法。为什么会这样?

我发现我可以改用assertTrue(true),但看起来仍然不合逻辑。

@Test
 public void testSetterForeignWord(){
  try {
   card.setForeignWord("");
   fail();
  } catch (IncorrectArgumentForSetter ex){
  }

 // assertTrue(true);
 }

【问题讨论】:

  • 只需使用 return 语句 - 在大多数情况下,它将作为 pass() 传递。
  • 一些测试系统 (perl Test::Simple) 计数通过和失败的断言。然而,Junit 会计算通过和失败的 测试方法 的数量。因此,Junit 对 pass 方法的用途不同。

标签: java junit


【解决方案1】:

只要您的测试完成并通过,请致电 return 声明。

【讨论】:

  • +1 必须是正确答案(在大多数情况下,除了预期、超时等)
  • 似乎确实是结束测试的最简单和可用的方法。
【解决方案2】:

只要测试没有抛出异常,它就会通过,除非您的@Test 注释指定了预期的异常。我想pass() 可能会抛出一个特殊的异常,JUnit 总是将其解释为通过,从而使测试短路,但这会违背测试的通常设计(即假设成功并且只有在断言失败时才会失败)并且,如果人们认为最好使用pass(),它将显着减慢大量通过测试的速度(由于创建异常的开销)。失败的测试不应该是常态,所以如果他们有这样的开销也没什么大不了的。

请注意,您的示例可以这样重写:

@Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
  card.setForeignWord("");
}

此外,您应该支持使用标准 Java 异常。你的IncorrectArgumentForSetter 应该是IllegalArgumentException

【讨论】:

  • fail() 方法和 assertX() 方法实际上只是抛出一个 AssertionError,这会导致测试方法不干净地退出。这就是为什么成功返回表明成功......
  • -1 - pass() 方法没有做任何事情 - 它立即退出测试,没有例外。在大多数情况下,这实际上等同于 return 语句(预期的异常、超时等除外)。
  • @grigory:你说得对,pass() 方法不能什么都不做,以免调用它后测试可能会失败。所以我删除了那句话。
  • 感激不尽,帮助我摆脱了很多挫折!
【解决方案3】:

我认为这个问题需要一个更新的答案,因为这里的大多数答案都已经过时了。

首先是OP的问题:

我认为在 JUnit 中引入“预期异常”概念是一个糟糕的举动,因为该异常可以在任何地方引发,并且它会通过测试,所以我认为它已经被大家接受了。如果您抛出(并断言)非常特定于域的异常,它会起作用,但我只在处理需要绝对完美无瑕的代码时抛出这些类型的异常,--大多数 APIS 只会抛出内置异常,如 @ 987654322@ 或IllegalStateException。如果您进行的两个调用可能会引发这些异常,那么 @ExpectedException 注释会将您的测试标记为绿色,即使它是引发异常的错误行!

对于这种情况,我编写了一个类,我相信这里的许多其他人都已经编写了一个 assertThrows 方法:

public class Exceptions {
    private Exceptions(){}

    public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
        try{
            actionThatShouldThrow.run();
            fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
        }
        catch(Exception e){
            if ( ! expectedException.isInstance(e)) {
                throw e;
            }
        }
    }
}

如果抛出异常,此方法只会返回,允许您在测试中进行进一步的断言/验证。

使用 java 8 语法,您的测试看起来非常好。下面是使用该方法对我们的模型进行的更简单的测试之一:

@Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
    //setup
    AxisRange range = new AxisRange(0,100);

    //act
    Runnable act = () -> range.setLowerBound(200);

    //assert
    assertThrows(IllegalArgumentException.class, act);
}

这些测试有点不靠谱,因为“act”步骤实际上并没有执行任何操作,但我认为意思还是很清楚的。

maven 上还有一个名为catch-exception 的小型库,它使用mockito 样式的语法来验证是否抛出了异常。它看起来很漂亮,但我不喜欢动态代理。也就是说,语法如此流畅,仍然很诱人:

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
// then: catch the exception if any is thrown 
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;

最后,对于我进入这个线程时遇到的情况,如果满足某些条件,有一种方法可以忽略测试。

现在我正在努力通过名为 JNA 的 java native-library-loading-library 调用一些 DLL,但我们的构建服务器在 ubuntu 中。我喜欢尝试使用 JUnit 测试来推动这种开发——即使它们在这一点上还远非“单元”——。如果我在本地机器上,我想要做的是运行测试,但如果我们在 ubuntu 上,则忽略测试。 JUnit 4 对此有一个规定,称为Assume

@Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true.
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 

    //setup
    URL url = DLLTestFixture.class.getResource("USERDLL.dll");
    String path = url.toURI().getPath();
    path = path.substring(0, path.lastIndexOf("/"));

    //act
    NativeLibrary.addSearchPath("USERDLL", path);
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);

    //assert
    assertThat(dll).isNotNull();
}

【讨论】:

  • 正如你所说,“act”没有做任何具体的事情,所以我们仍然不知道究竟是什么引发了异常,不管它是不是我们期望的行。在这种情况下,该示例非常易于测试和验证,但假设您的测试包含 Utility 方法,该方法在返回结果之前使用嵌套方法。除非 IDE 指出异常站点,否则仍然无法找到问题的根源
【解决方案4】:

我也在寻找 JUnit 的 pass 方法,以便我可以短路一些在某些场景中不适用的测试(有集成测试,而不是纯单元测试)。太糟糕了,它不在那里。

幸运的是,有一种方法可以有条件地忽略测试,这实际上更适合我使用 assumeTrue 方法的情况:

Assume.assumeTrue(isTestApplicable);

所以这里只有当 isTestApplicable 为真时才会执行测试,否则测试将被忽略。

【讨论】:

    【解决方案5】:

    不需要 pass 方法,因为当测试代码没有抛出 AssertionFailedException 时,单元测试用例将通过。

    fail() 方法实际上会抛出一个 AssertionFailedException 来使 testCase 失败,如果控制到达那一点。

    【讨论】:

    • 我认为它实际上是一个 junit.framework.AssertionFailedError。
    • 错误情况如何。说我从 webdriver 获取元素不可见异常。我应该捕获异常并返回。
    【解决方案6】:

    我认为这个问题是对测试执行过程的一点误解造成的。在 JUnit(和其他测试工具)中,结果是按方法计算的,而不是按断言调用计算的。没有计数器来跟踪执行了多少通过/失败的assertX

    JUnit 分别执行每个测试方法。如果方法成功返回,则测试注册为“通过”。如果发生异常,则测试注册为“失败”。在后一种情况下,可能有两个子情况:1)JUnit 断言异常,2)任何其他类型的异常。第一种情况下状态为“失败”,第二种情况下状态为“错误”。

    Assert 类中,许多速记方法可用于抛出断言异常。换句话说,Assert 是 JUnit 异常的抽象层。

    比如这是assertEqualsGitHub上的源码:

    /**
     * Asserts that two Strings are equal.
     */
    static public void assertEquals(String message, String expected, String actual) {
        if (expected == null && actual == null) {
            return;
        }
        if (expected != null && expected.equals(actual)) {
            return;
        }
        String cleanMessage = message == null ? "" : message;
        throw new ComparisonFailure(cleanMessage, expected, actual);
    }
    

    如你所见,如果相等则什么都不会发生,否则会抛出异常。

    所以:

    assertEqual("Oh!", "Some string", "Another string!");
    

    只需抛出一个ComparisonFailure 异常,JUnit 将捕获该异常,然后

    assertEqual("Oh?", "Same string", "Same string");
    

    什么都不做。

    总之,像pass() 这样的东西没有任何意义,因为它没有做任何事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-20
      • 2011-01-23
      • 2012-10-05
      • 1970-01-01
      • 1970-01-01
      • 2016-01-08
      • 1970-01-01
      相关资源
      最近更新 更多