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