最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - How can I get similar behavior to @Isolated on a test class, but where the test methods in said class run concurrently wi

programmeradmin1浏览0评论

My case is as follows:

  • I have several test classes to run
  • I want most of them all to run in parallel, and all tests inside to run in parallel too
  • I want one specific test class to run isolated from the others, but tests in them to run in parallel too

Using JUnit5, my junit-platform.properties are:

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.mode.classes.default=concurrent

My first approach was to annotate test class I wanted to be separated with @Isolated, but doing that resulted in all tests inside this class to be run sequentially too, which I need to avoid, because those tests are long-running

What could be the other way to achieve this partial sequentiality?

My case is as follows:

  • I have several test classes to run
  • I want most of them all to run in parallel, and all tests inside to run in parallel too
  • I want one specific test class to run isolated from the others, but tests in them to run in parallel too

Using JUnit5, my junit-platform.properties are:

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.mode.classes.default=concurrent

My first approach was to annotate test class I wanted to be separated with @Isolated, but doing that resulted in all tests inside this class to be run sequentially too, which I need to avoid, because those tests are long-running

What could be the other way to achieve this partial sequentiality?

Share Improve this question edited Feb 10 at 17:41 Slaw 46.3k8 gold badges62 silver badges99 bronze badges asked Feb 10 at 17:34 kkamikkami 231 silver badge4 bronze badges 3
  • You have a pretty unusual scenario, but something I would try is to create to separate suites. One suite would include only the isolated class you want and the other the rest of classes. I expect (not tried) that Junit does run suites as separate blocks sequentially but only testing will tell. – silver_mx Commented Feb 22 at 17:10
  • 2 Neither the JUnit Platform nor the JUnit Jupiter engine currently support this out of the box, see this GitHub discussion. I have created JUnit feature request #4346 on your behalf. – kriegaex Commented Feb 26 at 5:56
  • Thank you, I will keep and eye on this discussion and feature request! Solution below seems to work, but if it was implemented as a feature in the Isolated annotation itself, it would be wonderful. – kkami Commented Feb 28 at 12:28
Add a comment  | 

1 Answer 1

Reset to default 2 +50

I'm guessing in this class there's a particular set of resources which is being modified in a @BeforeAll and reset in an @AfterAll method in a way which is incompatible with other test classes but self consistent for all methods in the class in question.

The problem is caused because @Isolated is essentially an alias for @ResourceLock(Resources.GLOBAL), and that annotation is inherited by all the test methods in the class.

As far as I'm aware it's not possible to acquire a lock in a @BeforeAll method only to release it in an @AfterAll method, at least not with the annotation-based locks controlled by @ResourceLock and co.

If you're prepared to have the parallelizable test classes share a common base class (or manually add @BeforeAll and @AfterAll methods to them), there is a way to acheive what you want. The solution is based on a ReadWriteLock, and on the fact that parallel read access is allowed, but read-write access is sequentialized.

First, a utility class to help with sequentialized access:

public class Sequentializer {
    private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();

    public static void beforeParallelClass() {
        LOCK.readLock().lock();
    }

    public static void afterParallelClass() {
        LOCK.readLock().unlock();
    }

    public static void beforeIsolatedClass() {
        LOCK.writeLock().lock();
    }

    public static void afterIsolatedClass() {
        LOCK.writeLock().unlock();
    }
}

Next, a base class for parallel tests:

public class ParallelTestBase {
    @BeforeAll
    public static void beforeAll() {
        Sequentializer.beforeParallelClass();
    }

    @AfterAll
    public static void afterAll() {
        Sequentializer.afterParallelClass();
    }
}

Finally, (optional) a base class for test classes which should run separately from all other code:

public class IsolatedTestBase {

    @BeforeAll
    static void setUpBeforeClass() {
        Sequentializer.beforeIsolatedClass();
    }

    @AfterAll
    static void tearDownAfterClass() {
        Sequentializer.afterIsolatedClass();
    }
}

If you're doing complex setup and teardown in the test classes, you may want to call the appropriate Sequentializer methods explicitly rather than relying on inheritance.

Alternatively, you could build the locking mechanism into whatever resource is being modified by the test classes in question.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论