TestNG parallel classesAndMethods without XML - java

I'm trying to have both classes and methods running in parallel.
For example:
Method Tests
public class MethodTests(){
#Test(groups = "testMe")
public void methodTestOne(){
...
}
#Test(groups = "testMe")
public void methodTestTwo(){
...
}
}
Class Tests
-> Hoping the Test annotation on the class level would do it
#Test
public class ClassTests(){
#Test(groups = "testMe")
public void classTestOne(){
...
}
#Test(groups = "testMe")
public void classTestTwo(){
...
}
}
I've included the surefire-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<parallel>all</parallel>
<threadCount>${threads}</threadCount>
...
</plugin>
Note: I've also tried classesAndMethods
I'm running from the command line like this:
mvn clean verify -Dgroups=testMe -Dthreads=3
I'm trying to accomplish the classTests run on one thread, and the method tests use a different thread after being complete.
Purpose:
In the beforeClass, I'm setting up the test, and then quickly asserting multiple things on a page, If one fails, I want it to still test the other things on the page.
Where as, if the method tests fail, I need it to completely stop.
I need both scenarios, and I do not want to use any XML.

I am not sure I quite understand the use case. But the only combinations of parallelism supported by TestNG are as below
tests - causes #Test methods inside tags to run in parallel.
instances - Causes #Test methods inside test class instances to run in parallel.
classes - causes test classes to run in parallel
methods - causes multiple #Test methods to run in parallel
I dont remember seeing something called all. I think that's applicable only to the JUnit provider for Maven surefire plugin. Please see here.
For your scenario as long as you have the #BeforeClass(alwaysRun=true) it would be executed for all groups and it would prevent the test methods that are dependent on the before class to be skipped.
The value that you should be using is classes, like this : <parallel>classes</parallel>

Related

Spring Boot / JUnit, run all unit-tests for multiple profiles

I have a BaseTest class which consists of several tests. Each test shall be executed for EVERY profile I list.
I thought about using Parameterized values such as:
#RunWith(Parameterized.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
// #ActiveProfiles("h2-test") // <-- how to iterate over this?
public abstract class BaseTest {
#Autowired
private TestRepository test;
// to be used with Parameterized/Spring
private TestContextManager testContextManager;
public BaseTest(String profile) {
System.setProperty("spring.profiles.active", profile);
// TODO what now?
}
#Parameterized.Parameters
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList<>();
params.add(new Object[] {"h2-test" });
params.add(new Object[] {"mysql-test" });
return params;
}
#Before
public void setUp() throws Exception {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
// maybe I can spinup Spring here with my profile?
}
#Test
public void testRepository() {
Assert.assertTrue(test.exists("foo"))
}
How would I tell Spring to run each test with these different profiles? In fact, each profile will talk to different datasources (in-memory h2, external mysql, external oracle, ..) so my repository/datasource has to be reinitialized.
I know that I can specify #ActiveProfiles(...) and I can even extend from BaseTest and override the ActiveProfile annotation. Although this will work, I only show a portion of my test-suite. Lots of my test-classes extend from BaseTest and I don't want to create several different profile-stubs for each class. Currently working, but ugly solution:
BaseTest (#ActiveProfiles("mysql"))
FooClassMySQL(annotation from BaseTest)
FooClassH2(#ActiveProfiles("h2"))
BarClassMySQL(annotation from BaseTest)
BarClassH2(#ActiveProfiles("h2"))
Thanks
For what it's worth:
My use case was to run a specific test class for multiple spring profiles, this is how I achieved it:
#SpringBootTest
abstract class BaseTest {
#Test void doSomeTest() {... ARRANGE-ACT-ASSERT ...}
}
#ActiveProfiles("NextGen")
class NextGenTest extends BaseTest {}
#ActiveProfiles("Legacy")
class LegacyTest extends BaseTest {}
If you use Maven you can actually specify active profile from command line (or env variable if needed):
mvn clean test -Dspring.profiles.active=h2-test
The approach with parameterized test may not work in this case, because profile has to be specified before Spring boots up its context. In this case when you run parameterized integration test the context will be already booted up before test runner starts running your test. Also JUnit's parameterized tests were invented for other reasons (running unit tests with different data series).
EDIT: Also one more thing - when you decide to use #RunWith(Parameterized.class) you wont be able to use different runner. In many cases (if not all if it comes to integration testing) you want to specify different runner, like SpringRunner.class - with parameterized test you wont be able to do it.
Spring profiles are not designed to work in this way.
In your case, each profile uses a specific datasource.
So each one requires a Spring Boot load to run tests with the expected datasource.
In fact, what you want to do is like making as many Maven build as Spring profiles that you want to test.
Besides, builds in local env should be as fast as possible.
Multiplying automated tests execution by DBMS implementation that requires a Spring Boot reload for each one will not help.
You should not need to specify #ActiveProfiles .
It looks rather like a task for a Continuous Integration tool where you could define a job that executes (sequentially or parallely) each Maven build by specifying a specific Spring Boot profile :
mvn clean test -Dspring.profiles.active=h2
mvn clean test -Dspring.profiles.active=mysql
etc...
You can also try to perform it in local by writing a script that performs the execution of the maven builds.
But as said, it will slowdown your local build and also complex it.

JUnit Tests (Integrations Tests) only on local machine [duplicate]

When writing code that interacts with external resources (such as using a web service or other network operation), I often structure the classes so that it can also be "stubbed" using a file or some other input method. So then I end up using the stubbed implementation to test other parts of the system and then one or two tests that specifically test calling the web service.
The problem is I don't want to be calling these external services either from Jenkins or when I run all of the tests for my project (e.g. "gradle test"). Some of the services have side effects, or may not be accessible to all developers.
Right now I just uncomment and then re-comment the #Test annotation on these particular test methods to enable and disable them. Enable it, run it manually to check it, then remember to comment it out again.
// Uncomment to test external service manually
//#Test
public void testSomethingExternal() {
Is there is a better way of doing this?
EDIT: For manual unit testing, I use Eclipse and am able to just right-click on the test method and do Run As -> JUnit test. But that doesn't work without the (uncommented) annotation.
I recommend using junit categories. See this blog for details : https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0.
Basically, you can annotate some tests as being in a special category and then you can set up a two test suites : one that runs the tests of that category and one that ignores tests in that category (but runs everything else)
#Category(IntegrationTests.class)
public class AccountIntegrationTest {
#Test
public void thisTestWillTakeSomeTime() {
...
}
#Test
public void thisTestWillTakeEvenLonger() {
....
}
}
you can even annotate individual tests"
public class AccountTest {
#Test
#Category(IntegrationTests.class)
public void thisTestWillTakeSomeTime() {
...
}
Anytime I see something manually getting turned on or off I cringe.
As far as I can see you use gradle and API for JUnit says that annotation #Ignore disables test. I will add gradle task which will add #Ignore for those tests.
If you're just wanting to disable tests for functionality that hasn't been written yet or otherwise manually disable some tests temporarily, you can use #Ignore; the tests will be skipped but still noted in the report.
If you are wanting something like Spring Profiles, where you can define rulesets for which tests get run when, you should either split up your tests into separate test cases or use a Filter.
You can use #Ignore annotation to prevent them from running automatically during test. If required, you may trigger such Ignored tests manually.
#Test
public void wantedTest() {
return checkMyFunction(10);
}
#Ignore
#Test
public void unwantedTest() {
return checkMyFunction(11);
}
In the above example, unwantedTest will be excluded.

Running Tests in Parallel with Junit [duplicate]

This question already has answers here:
Running junit tests in parallel in a Maven build?
(10 answers)
Closed 7 years ago.
I would like to run every method annotated with #Test, across multiple classes, at the same time. For some cases, I would like to limit this, and say that only 100 total can run at any one time. I would like methods with #BeforeClass annotations to be run once before any Test in a class runs, and I would like #AfterClass annotations to be run once after all Tests in a class run. I would like System.out, System.err, and Exceptions to be appropriately buffered/captured rather than written out, so that they don't interleave, and I can read the final output and understand what happened.
Does this exist? I have a large number of independent test cases, and my application is (I believe) threadsafe. None of these tests have dependencies out of the JVM, and I want to finish them as quickly as possible, given my hardware.
If this doesn't exist, is there a concrete reason why not? How much time is lost by junit users worldwide because this isn't easy? Can I build it into Junit? In my mind, this should be as simple as a single flag, and it "just works".
You can accomplish this with JUnit's ParallelComputer (note it's still considered experimental). It's a pretty simple implementation which is backed by the java.util.concurrent.ExecutorService API. If you're curious how it works, check out the source.
Basically you call JUnitCore.runClasses(Computer, Classes ...) and pass in a ParallelComputer object for the first argument.
Example usage:
import org.junit.Test;
import org.junit.experimental.ParallelComputer;
import org.junit.runner.JUnitCore;
public class ParallelComputerExample {
#Test
public void runAllTests() {
Class<?>[] classes = { ParallelTest1.class, ParallelTest2.class };
// ParallelComputer(true,true) will run all classes and methods
// in parallel. (First arg for classes, second arg for methods)
JUnitCore.runClasses(new ParallelComputer(true, true), classes);
}
public static class ParallelTest1 {
#Test
public void test1a() {
lookBusy(3000);
}
#Test
public void test1b() {
lookBusy(3000);
}
}
public static class ParallelTest2 {
#Test
public void test2a() {
lookBusy(3000);
}
#Test
public void test2b() {
lookBusy(3000);
}
}
public static void lookBusy(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
The above code will run in 3 seconds because all methods and classes are ran in parallel.
This will run in 6s (because all classes are in parallel).
JUnitCore.runClasses(new ParallelComputer(true, false), classes);
This will also run in 6s (because all methods are in parallel).
JUnitCore.runClasses(new ParallelComputer(false, true), classes);
Yes, You can.
If you are using maven. You can take help of
maven-surefire-plugin
In Spring,
You can check this Link
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<parallel>classes</parallel>
<threadCount>5</threadCount>
</configuration>
</plugin>
</plugins>
</build>
Solution 2: Junit4 provides parallel feature using ParallelComputer
JUnit Toolbox provides JUnit runners for parallel execution of tests.
In order to not intermix output to System.err and System.out you have to start tests in separate JVMs, because System.err and System.out are global.

Extending from Suite Runner vs BlockJUnit4Runner while defining some TestRules

I have a requirement to write many tests. I have extended Suite Runner of JUnit in order to be able to add new annotations where I can mention several Prerequisite classes which will be executed before any of the tests or setups get executed. My Typical test looks like this.
#RunWith(CustomSuiteRunner.class)
#BeforeSuite(Prerequisite.class)
#AfterSuite(CleanupOperations.class)
#Suite.SuiteClasses({
SimpleTests.class,
WeatherTests.class
})
public class SimpleSuite {
}
I have overridden public void run(final RunNotifier notifier) to add code the required code to trigger prerequisites and cleanup operations mentioned in BeforeSuite and AfterSuite annotation.
Now, I'm trying to find out how I can achieve the same by extending BlockJUnit4Runner? I can't find any method equivalent to run that starts the execution to override the behaviour. There is runChild which gets triggered before a child gets executed.
The reason I'm looking for this is I'm trying created several rules in an Interface and make my tests implement that so that they will be available, however as Interface elements are static and final JUnit is ignoring these. In another Question I asked today I got answer that I can make JUnit consider rules mentioned in an Interface by extending BlockJUnit4Runner and overriding getTestRules().
So, Here is what I'm trying find out.
Is it possible to extend BlockJUnit4Runner to make it take a list of tests and run them as suite and also run some code before any tests get execute and after all tests are executed?
How can I extend Suite Runner to consider TestRules defined in an implemented interface?
It is pretty much possible to extend BlockJUnit4Runner and make it take a list of tests and run them as suite with required test dependencies handled within the extended runChild() method
public class CustomRunner extends BlockJUnit4ClassRunner {
private List<String> testsToRun = Arrays.asList(new String[] { “sample1” });
public CustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
public void runChild(FrameworkMethod method, RunNotifier notifier) {
//Handle any dependency logic by creating a customlistener registering notifier
super.runChild(method,notifier);
}
}

Using JUnit RunListener in IntelliJ IDEA

I'm working on project where I need to perform some action before running each JUnit test. This problem was solved using RunListener that could be added to the JUnit core. The project assembly is done using Maven, so I have this lines in my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>cc.redberry.core.GlobalRunListener</value>
</property>
</properties>
</configuration>
</plugin>
So, everything works using:
mvn clean test
But when tests are started using IntelliJ (using its internal test runner) the actions coded in our RunListener are not executed, so it is impossible to perform testing using IntelliJ infrastructure.
As I see, IntelliJ does not parse this configuration from pom file, so is there a way to explicitly tell IntelliJ to add RunListener to JUnit core? May be using some VM options in configuration?
It is much more convenient to use beautiful IntelliJ testing environment instead of reading maven output.
P.S. The action I need to perform is basically a reset of static environment (some static fields in my classes).
I didn't see a way to specify a RunListener in Intellij, but another solution would be to write your own customer Runner and annotate #RunWith() on your tests.
public class MyRunner extends BlockJUnit4ClassRunner {
public MyRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
// run your code here. example:
Runner.value = true;
super.runChild(method, notifier);
}
}
Sample static variable:
public class Runner {
public static boolean value = false;
}
Then run your tests like this:
#RunWith(MyRunner.class)
public class MyRunnerTest {
#Test
public void testRunChild() {
Assert.assertTrue(Runner.value);
}
}
This will allow you to do your static initialization without a RunListener.

Categories