即使其中一个断言失败,也会在junit4中继续执行测试

时间:2012-04-19 04:58:16

标签: java junit4

我使用Jfunc构建了我现有的框架,即使在测试用例中的一个断言失败时也提供了继续执行的工具。 Jfunc使用junit 3.x框架。但是现在我们正在迁移到junit4,所以我不能再使用Jfunc并用junit 4.10 jar替换它。
现在的问题是因为我们在框架中广泛使用了jfunc,而对于junit 4,我们希望使代码继续执行,即使其中一个断言在测试用例中失败。
有没有人对此有任何建议/想法,我知道在junit中测试需要更加原子化,即每个测试用例一个断言,但由于某种原因我们不能在我们的框架中这样做。

7 个答案:

答案 0 :(得分:60)

您可以使用ErrorCollector规则执行此操作。

要使用它,首先将规则添加为测试类中的字段:

public class MyTest {
    @Rule
    public ErrorCollector collector = new ErrorCollector();

    //...tests...
}

然后通过调用collector.checkThat(...)来替换你的断言。

e.g。

@Test
public void myTest() {
    collector.checkThat("a", equalTo("b"));
    collector.checkThat(1, equalTo(2));
}

答案 1 :(得分:17)

我也使用ErrorCollector,但也使用assertThat并将它们放在try catch块中。

import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;

@Rule
public ErrorCollector collector = new ErrorCollector();

@Test
public void calculatedValueShouldEqualExpected() {
    try {
        assertThat(calculatedValue(), is(expected));
    } catch (Throwable t) {
        collector.addError(t);
        // do something
    }
}

答案 2 :(得分:3)

您也可以使用assertj - soft assertion

@Test
public void testCollectErrors(){
   SoftAssertions softly = new SoftAssertions();
   softly.assertThat(true).isFalse();
   softly.assertThat(false).isTrue();
   // Don't forget to call SoftAssertions global verification !
   softly.assertAll();
}

还有其他方式使用它而无需手动调用softly.assertAll();

  1. with rule
  2. with autoclosable
  3. Using the static assertSoftly method

答案 3 :(得分:1)

使用try / finally块。这适用于我的情况:

...
try {
    assert(...)
} finally {
    // code to be executed after assert
}
...

答案 4 :(得分:0)

尝试-捕获,在“尝试”中使用断言,在“捕获”中,将可能的错误添加到集合中。 然后在测试结束时在tearDown()中抛出异常。 因此,如果断言中存在失败/错误,它将被捕获并且测试将继续。 (示例中的集合是静态的,您还可以在setUp()中为每个@Test创建新实例)

    public static List<String> errors = new ArrayList<>();


    try {
        //some assert...
    }
    catch (AssertionError error) {
        errors.add(error.toString());
    }



    @After
    public void tearDown() {

        try {
            if (!errors.isEmpty()) {
                throw new AssertionError(errors);
            }
        }
        finally {
            //empty list because it's static, alternatively make instance for each test in setUp()
            errors.clear();
        }
    }

答案 5 :(得分:0)

我创建了自己的简单断言类。易于扩展您的用例:

public class MyEquals {

public static void checkTestSummary(MyTestSummary myTestSummary) {
    final List<MyTestResult> conditions = myTestSummary.getTestResults();
    final int total = conditions.size();

    final boolean isSuccessful = myTestSummary.isSuccessful();
    if (isSuccessful) {
        System.out.println(format("All [%s] conditions are successful!", total));
    } else {
        final List<MyTestResult> failedConditions = conditions.stream().filter(MyTestResult::isTestResult).collect(Collectors.toList());
        System.out.println(format("\nNot yet.. [%s out of %s] conditions are failed", failedConditions.size(), total));
    }

    if (!isSuccessful) {
        for (int i = 0; i < total; i++) {
            final MyTestResult myTestResult = conditions.get(i);
            if (myTestResult.isTestResult()) {
                System.out.println(format("  Success [%s of %s] => Expected %s Actual %s Good!", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
            } else {
                System.out.println(format("!! Failed [%s of %s] => Expected %s Actual %s", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
            }
        }
    }

    assertTrue(isSuccessful);
}

public static void myAssertEquals(MyTestSummary myTestSummary, Object expected, Object actual) {
    if (checkEquals(expected, actual)) {
        assertEquals(expected, actual);
        myTestSummary.addSuccessfulResult(expected, actual);
    } else {
        myTestSummary.addFailedResult(expected, actual);
        myTestSummary.setSuccessful(false);
    }
}

public static boolean checkEquals(Object value1, Object value2) {
    if (value1 == null && value2 == null) {
        return true;
    } else if (value1 != null && value2 == null) {
        return false;
    } else if (value1 == null && value2 != null) {
        return false;
    } else if (value1 != null && value2 != null) {
        return value1.equals(value2);
    }
    return false;
}

}

@Builder
@Value
public class MyTestResult {

    String expected;

    String actual;

    boolean testResult;

 }



@Data
public class MyTestSummary {

private boolean successful = true;

private List<MyTestResult> testResults = new ArrayList<>();

public MyTestSummary() {
}

public void addSuccessfulResult(Object expected, Object actual) {
    getTestResults().add(MyTestResult.builder()
        .expected(String.valueOf(expected))
        .actual(String.valueOf(actual))
        .testResult(true)
        .build()
    );
}

public void addFailedResult(Object expected, Object actual) {
    getTestResults().add(MyTestResult.builder()
        .expected(String.valueOf(expected))
        .actual(String.valueOf(actual))
        .testResult(false)
        .build()
    );
}
}

junit 测试中的使用

@Test
public void testThat() {
    MyTestSummary myTestSummary = new MyTestSummary();
    myAssertEquals(myTestSummary, 10, 5 + 5);
    myAssertEquals(myTestSummary, "xxx", "x" + "x");
    checkTestSummary(myTestSummary);
}

输出:

Not yet.. [1 out of 2] conditions are failed
Success [1 of 2] => Expected 10 Actual 10 Good!
!! Failed [2 of 2] => Expected xxx Actual xx

 org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
 Expected :true
 Actual   :false

答案 6 :(得分:-1)

另一个选择是可观察模式与lambda表达式结合使用。您可以使用上述类似的内容。

public class MyTestClass {

    private final List<Consumer<MyTestClass>> AFTER_EVENT = new ArrayList<>();

    @After
    public void tearDown() {
        AFTER_EVENT.stream().forEach(c -> c.accept(this));
    }

    @Test
    public void testCase() {
        //=> Arrange
        AFTER_EVENT.add((o) -> {
            // do something after an assertion fail.
        }));

        //=> Act

        //=> Assert
        Assert.assertTrue(false);
    }
}