testng icon indicating copy to clipboard operation
testng copied to clipboard

Feature Request: Add similar functionality to junit ResourceLock annotation

Open bdrx312 opened this issue 3 months ago • 3 comments

JUnit has a @ResourceLock annotation (https://docs.junit.org/current/api/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLock.html) that can be added to a test to prevent scheduling at the same time of any tests that utilize the shared resource. There are several times that I have had a set of tests that I do not want to run at the same time as each other but still want to run in parallel with other tests. The tests are not dependent on each other. I have not found an elegant way to make these tests run at mutually exclusive. Please add a way to mark that certain tests will not be scheduled to run at the same time as each other.

bdrx312 avatar Sep 02 '25 13:09 bdrx312

@bdrx312

I have not found an elegant way to make these tests run at mutually exclusive.

There is a way. you need to learn the next:

  • parallel = methods to execute test-cases (test-methods) in parallel.
  • @Test(singleThreaded = true) - annotation for the class level to run everything in 1 thread, even if parallel=methods
  • @Test(alwaysRun = true) - to execute test even if dependent failed
  • @Test(ignoreMissingDependencies = true) - to execute test even if dependent was not included in suite

I assume you use parallel = methods.

Case 1 (single shared resource in write mode). Example: set of tests which write data in a common file. Solution: Put all such tests in a single class, set @Test(singleThreaded = true) at the class level. All tests in this class will run one-by-one, but in parallel with other methods from other classes.

Case 2 (single shared resource in read and write mode). Example: set of tests which write data in a common file AND another set of tests which read this data (they can run in parallel) Solution: a) Put all tests with write access into a single class, set @Test(singleThreaded = true, groups = "resource1") at the class level. b) All tests with a 'read' mode put into another class (without any annotation), set @Test(dependsOnGroups = "resource1", alwaysRun = true, ignoreMissingDependencies = true) at the test-method TestNG will execute all tests with the 'write' access' and then will execute remaining tests with a read access. Other tests from your suite will be executed in parallel with previous. Notes: all tests with the 'write' mode will 'inherit' the groups annotation from class. So optionally you can set this annotatin at the testMethod level. Also, if you have only 1 test with the 'write' mode, you can put that test in any class with @Test(groups = "resource1")

Case 3 (multiple shared resource in read and write mode). Tests can belong to several groups and tests can depends on several groups. You can combine this to create advanced scenarios.

@Test(singleThreaded = true, groups = "resource1")
public class WriteResource1Tests {...}

@Test(singleThreaded = true, groups = "resource2")
public class WriteResource2Tests {...}

public class ReadResourcesTests {
    @Test(dependsOnGroups = "resource1", alwaysRun = true, ignoreMissingDependencies = true)
    void readResource1test1(){...}

    @Test(dependsOnGroups = "resource1", alwaysRun = true, ignoreMissingDependencies = true)
    void readResource1test2(){...}

    @Test(dependsOnGroups = "resource2", alwaysRun = true, ignoreMissingDependencies = true)
    void readResource2(){...}

    @Test(dependsOnGroups = {"resource1","resource2"}, alwaysRun = true, ignoreMissingDependencies = true)
    void readResource1and2(){...}
}

I've put an example project in attachments for the case 3: test.zip

P.S. you can also use @Test(dependsOnMethods={...} ) to organize execution order (inside class). Also I want to avoid usage of the @Test(priority = ) because in most cases it will not work as you expect. Especially when you combine it with the groups. (priority is a global across suite, i.e. testng will execute all tests from all classes with priority 0 and then all tests from all classes with priority 1 and so on)

kool79 avatar Oct 04 '25 04:10 kool79

@kool79 Thank you so much for that feedback. I did not read the documentation close enough for @Test and did not realize that @Test(singleThreaded = true) on a class just made the tests in that class run in the same thread but still parallel to tests in other classes. Although that is not as clean as being able to annotate individual tests in a class with an annotation like @ResourceLock, I think utilizing singleThreaded could definitely work for me as a work around.

bdrx312 avatar Oct 04 '25 17:10 bdrx312

Actually after thinking a little more, I realized using @Test(singleThreaded = true) will work in a few select use cases but there are other cases that I don't really want to put into the same class for organizational clarity reasons.

bdrx312 avatar Oct 04 '25 17:10 bdrx312