JUnit4 fail()在这里,但是pass()在哪里?


82

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

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

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

 // assertTrue(true);
 }

7
只需使用return语句-在大多数情况下,它将作为pass()传递。
topchef 2010年

@topchef的单个评论击中了头,而其他所有人都在争论哪个可以接受,哪个不可以。

一些测试系统(perl Test :: Simple)对通过和失败的断言进行计数。但是,Junit会计算通过和失败的测试方法的数量。因此Junit在方法上没有相同的用途pass
兰德尔·惠特曼

Answers:


63

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

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

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

另外,您应该赞成使用标准Java异常。您IncorrectArgumentForSetter应该是一个IllegalArgumentException


4
fail()方法和assertX()方法实际上只是抛出一个AssertionError,这会导致测试方法异常退出。这就是为什么成功的回报表明成功的原因……
史蒂文·斯兰斯克

-1-pass()方法没有做任何事情-它立即退出测试,没有异常。在大多数情况下,这实际上等效于return语句(预期的异常,超时等除外)。
topchef 2010年

1
@grigory:您是对的,一个pass()方法不能只做任何事情,以免测试调用后可能失败。所以我删除了那句话。
ColinD

我感激不尽,帮助我摆脱了很多挫败感!
N00b Pr0grammer

70

return只要您的测试完成并通过,就可以拨打电话。


3
+1必须是正确答案(在大多数情况下,除了预期的情况,超时等)
topchef 2010年

似乎确实是结束测试的最简单和可用的方法。

7

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

首先,对OP的问题:

我认为,将“预期的例外”概念引入JUnit是一个不好的举动,因为它可以在任何地方引发,并且可以通过测试。如果您抛出(并断言)非常特定于域的异常,那么它会起作用,但是当我处理需要绝对完美的代码时,我只会抛出此类异常,-大多数APIS只会抛出诸如IllegalArgumentException或的内置异常。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,它使用模仿式语法来验证是否抛出了异常。看起来不错,但是我不喜欢动态代理。就是说,那里的语法是如此巧妙,它仍然很诱人:

// 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();
}

正如您所说的,“行为”没有做任何特定的事情,因此我们仍然不知道到底是什么引发了异常,无论这是我们所期望的行。在这种情况下,该示例非常容易进行测试和验证,但是可以想象您的测试包含在返回结果之前使用嵌套方法的Utility方法。除非IDE指示异常站点,否则仍然无法找到问题的根源
Farid

4

我也在寻找passJUnit的方法,以便我可以短路某些在某些情况下不适用的测试(有集成测试,而不是纯单元测试)。太糟糕了,它不存在。

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

Assume.assumeTrue(isTestApplicable);

因此,此处仅在isTestApplicable为true时才执行测试,否则将忽略测试。


2

不需要pass方法,因为当从测试代码中未引发AssertionFailedException时,单元测试用例将通过。

如果控制到达该点,则fail()方法实际上会引发AssertionFailedException来使testCase失败。


我认为这实际上是一个junit.framework.AssertionFailedError。
凯尔

错误情况如何?说我从Webdriver获取元素不可见的异常。我应该捕获异常并返回。
sasikumar

1

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

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

Assert该类中,有许多速记方法可用于引发断言异常。换句话说,Assert是JUnit异常之上的抽象层。

例如,这是的源代码assertEquals的GitHub

/**
 * 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()没有任何意义的,因为它什么也没做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.