【问题标题】:Failing a unit test if an exception is thrown in another thread如果在另一个线程中引发异常,则单元测试失败
【发布时间】:2018-01-27 07:58:33
【问题描述】:

目前,每当我需要响应另一个线程中抛出的异常而使测试失败时,我都会编写如下内容:

package com.example;

import java.util.ArrayList;
import java.util.List;
import org.testng.annotations.Test;

import static java.util.Arrays.asList;
import static java.util.Collections.synchronizedList;
import static org.testng.Assert.fail;

public final class T {
  @Test
  public void testFailureFromLambda() throws Throwable {
    final List<Throwable> errors = synchronizedList(new ArrayList<>());

    asList("0", "1", "2").parallelStream().forEach(s -> {
      try {
        /*
         * The actual code under test here.
         */
        throw new Exception("Error " + s);
      } catch (final Throwable t) {
        errors.add(t);
      }
    });

    if (!errors.isEmpty()) {
      errors.forEach(Throwable::printStackTrace);

      final Throwable firstError = errors.iterator().next();
      fail(firstError.getMessage(), firstError);
    }
  }
}

同步列表可以替换为AtomicReference&lt;Throwable&gt;,但通常代码几乎相同。

是否有任何标准(并且不那么冗长)的方法可以使用 Java 中提供的任何测试框架(TestNGJUnitHamcrestAssertJ 等.)?

【问题讨论】:

    标签: unit-testing junit testng hamcrest assertj


    【解决方案1】:

    默认情况下,当一个测试方法抛出异常时,TestNG 会失败。我相信同样的事情也会发生在 JUnit 上,如果它抛出意外的异常,它会将测试标记为 errored

    如果您要处理Streams,那么您需要将它包装在RuntimeException 变体中,这样Java 就不会抱怨。 TestNG 会自动使测试失败。

    这是一个示例:

    @Test
    public void testFailureFromLambdaRefactored() {
        asList("0", "1", "2").parallelStream().forEach(s -> {
            try {
            /*
            * The actual code under test here.
            */
                if (s.equals("2")) {
                    throw new Exception("Error " + s);
                }
            } catch (final Throwable t) {
                throw new RuntimeException(t);
            }
        });
    }
    

    这适用于涉及 lambda 和流的场景。一般来说,如果您想了解从 @Test 方法分离出来的新线程中发生的异常,则需要使用 ExecutorService

    这是一个示例:

    @Test
    public void testFailureInAnotherThread() throws InterruptedException, ExecutionException {
        List<String> list = asList("0", "1", "2");
        ExecutorService service = Executors.newFixedThreadPool(2);
        List<Future<Void>> futures = service.invokeAll(Arrays.asList(new Worker(list)));
        for (Future future : futures) {
            future.get();
        }
    
    }
    
    public static class Worker implements Callable<Void> {
        private List<String> list;
    
        public Worker(List<String> list) {
            this.list = list;
        }
    
        @Override
        public Void call() throws Exception {
            for (String s : list) {
                if (s.equals("2")) {
                    throw new Exception("Error " + s);
                }
            }
            return null;
        }
    }
    

    【讨论】:

    • 如果我想防止整个测试失败并在其中一个软断言中抛出异常时继续软断言怎么办?
    • @enissay - 默认情况下,SoftAssertions 只有在所有断言都经过验证后才会通过测试。
    • 这不是我的经验。也许我做错了什么。我已经发布了这个question,希望你能帮助我:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2016-06-22
    相关资源
    最近更新 更多