【问题标题】:Is there a way to report lingering threads after every test class? (junit/maven)有没有办法在每个测试课后报告挥之不去的线程? (junit/maven)
【发布时间】:2017-09-28 10:59:47
【问题描述】:

在编写不佳的遗留代码库中,单元测试调用的代码会启动永不停止的线程。在大多数情况下,它没有效果,但在某些情况下,它会大大减慢构建速度,在其他情况下,它会导致构建期间同一项目中的测试之间完全不清楚的副作用:例如测试 A 启动线程,然后 B 在同一个 JVM 中运行并以某种未定义的方式中断(修复是让 A 停止该线程)。

是否有一些工具可以与 junit 结合使用,以便在每个测试(或一个类中的一组测试)结束时,如果有任何线程仍在运行,它会导致测试失败?

这将使我们能够快速识别和修复所有现有案例,但也可以防止以这种方式编写新测试。

【问题讨论】:

  • 如果您要的是现有工具,那是离题的边缘。但是实现一个可以作为测试后套件检查运行的检查是微不足道的。
  • 不要认为有工具,但您可以使用java.lang.Thread.activeCount() 轻松自己完成,并在每次测试调用前后使用AspectJ 进行检查。这也可能是题外话,但绝对不是重复的@StephenC 你在滥用你的权力。
  • 其他人可以做到这一点:-)
  • @Alexandros - 我不会使用 AspectJ。我会在 Junit4 @After@AfterClass 钩子或类似的东西中进行检查。

标签: multithreading unit-testing junit4 maven-surefire-plugin


【解决方案1】:
public class FailOnLingeringThreadsTestBase
{
    private static Set<Thread> threadsBefore;

    @BeforeClass
    public static void takePhoto()
    {
        threadsBefore = Collections.unmodifiableSet(Thread.getAllStackTraces().keySet());
    }

    @AfterClass
    public static void spotTheDiffs()
    {
        Set<Thread> threadsAfter = Thread.getAllStackTraces().keySet();
        if (threadsAfter.size() != threadsBefore.size())
        {
            threadsAfter.removeAll(threadsBefore);
            throw new IllegalStateException("Lingering threads in test: " + threadsAfter);
        }
    }
}

【讨论】:

  • ...如果 junit 在所有测试之前/之后有一些垂直方式来整合它
  • 我告诉过你,你可以使用 AspectJ
  • ...这将是需要合并的第三个问题! :)
【解决方案2】:

显然 Maven/Surefire 允许您使用配置来挂钩侦听器!这是一种通过将检查实现为 org.junit.runner.notification.RunListener 的一部分来垂直集成检查的现实方法。

这是我现在使用的:

public class FailOnLingeringThreadsRunListener extends org.junit.runner.notification.RunListener
{
    private Set<Thread> threadsBefore;

    @Override
    public synchronized void testRunStarted(Description description) throws Exception
    {
        threadsBefore = takePhoto();
        super.testRunStarted(description);
    }

    @Override
    public synchronized void testRunFinished(Result result) throws Exception
    {
        super.testRunFinished(result);

        Set<Thread> threadsAfter = spotTheDiffs(threadsBefore);

        // only complain on success, as failures may have caused cleanup code not to run...
        if (result.wasSuccessful())
        {
            if (!threadsAfter.isEmpty())
                throw new IllegalStateException("Lingering threads in test: " + threadsAfter);
        }
    }

    public static Set<Thread> takePhoto()
    {

        return Collections.unmodifiableSet(Thread.getAllStackTraces().keySet());
    }

    @AfterClass
    public static Set<Thread> spotTheDiffs(Set<Thread> threadsBefore)
    {
        Set<Thread> threadsAfter = Thread.getAllStackTraces().keySet();
        if (threadsAfter.size() != threadsBefore.size())
        {
            threadsAfter.removeAll(threadsBefore);
            return Collections.unmodifiableSet(threadsAfter);
        }

        return Collections.emptySet();
    }
}

这是我在构建中启用它的方法:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>testutil.FailOnLingeringThreadsRunListener</value>
                        </property>
                    </properties>
                </configuration>
            </plugin>
...

【讨论】:

    猜你喜欢
    • 2016-04-18
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 2017-02-07
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多