Using JUnit RunListener in IntelliJ IDEA - java

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.

Related

JUnit 5 #Tag does not work as expected with #BeforeEach/#AfterEach

Have a simple math operations test suite developed with JUnit 5.
I use two tags #Tag("add") and #Tag("minus").
With maven and surefire plugin I select the tag for the tests.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration combine.children="append">
<excludedGroups></excludedGroups>
<groups>add</groups>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
</dependency>
</dependencies>
</plugin>
When I do the mvn test on the terminal it will execute only the tests marked by the #Tag("add") but for some reason will execute the #BeforeEach and #AfterEach tagged exclusively with #Tag("minus")
#Tag("minus")
#BeforeEach
void beforeEach(TestInfo test) { /* code */ }
#Tag("minus")
#AfterEach
void afterEach(TestInfo test) { /* code */ }
Since the expected behaviour was not working, I even forced with <excludedGroups>, changed from empty value to <excludedGroups>minus</excludedGroups> on pom.xml, still not worked.
There is something wrong on pom.xml that I'm missing?
A conflict between #Tag and #BeforeEach plus #AfterEach?
#Tag is meant for test classes and methods. It has nothing to do with setup/teardown of said tests.
You could either split those tests into separate test classes or you could leverage Nested Test. Nested tests could look something like this:
#DisplayName("A stack")
class MathTest {
#Nested
#DisplayName("when new")
#Tag("add")
class Add {
#BeforeEach
void setupAdding() {
// ...
}
#Test
#DisplayName("can add")
void canAdd() {
// ...
}
}
#Nested
#DisplayName("minus")
#Tag("minus")
class Minus {
#BeforeEach
void setupMinus() {
// ...
}
#Test
#DisplayName("can subtract")
void testMinus() {
// ...
}
}
}
I think that the #Tag annotation was conceived just to clasify your tests following a common characteristic. If you need different setUp() and teardown() I guess the righ way to go is to separate them in different test classes, not with the tag annotation.
In the documentation it is describes it can be used in a test class or a test method:
https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Tag.html

TestNG parallel classesAndMethods without XML

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>

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.

System.out.print() doesn't show anything in test methods

I'm trying to print some data with System.out in my unit tests (#Test mehotds), but it is not showing anything. However, it works properly in #Before method. I'm using JUnit with Maven Surefire plugin.
public class MyTests {
#Before
void init(){
System.out.println("Initializing some data..."); // <- It works.
}
#Test
void shouldRemoveSeries() {
System.out.println("TEST: Should remove series"); // <- It doesn't.
}
}
maven-surefire-plugin configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.15</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
Thanks.
Ran into this as well. I'm using gradle to manage my tasks and I put this in at the end of by build.gradle file :
test {
testLogging.showStandardStreams = true
}
Now I see System.out.println(whateves).
To get the output of your written Tests via System.out.println you need to configure maven-surefire-plugin to redirect this output into a file which can be achieved by using the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
The option redirectTestOutputToFile will redirect the output of System.out.println etc. into a file which is separately created:
Excerpt from the docs:
Set this to "true" to redirect the unit test standard output to a file
(found in reportsDirectory/testName-output.txt).
Apart from that a System.out.println does not make sense in a unit test in general.
Use Log
private static Logger log = Logger.getLogger(LoggingObject.class);
log.info("I'm starting");
or System.setOut()
private final PrintStream stdout = System.out;
private final ByteArrayOutputStream output = new ByteArrayOutputStream();
private TerminalView terminalview;
The -Dtest=* command line option of Maven appears to trigger the show of stdout in unit tests.
By convention, the stdout shows in target/surefire-reports/*-output.txt. Apparently, the Surefire plugin developers could not reuse stdout for communication of many things between the tests and the framework.
The problem is the name of your test class. To be recognized in the test phase within the build (by the Maven surefire plugin), it must be named "*Test":
Inclusions and Exclusions of Tests
I made i little trick in separate non-test class. It is not that smooth as logger, but if you are looking for quick solution in Spring Boot you can use this.
PrintForTest.java
import org.springframework.stereotype.Controller;
#Controller
public class PrintForTest {
public static void print(String input){
System.out.println(input);
}
}
MainTest.java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.Assert;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#SpringBootTest
#RunWith(SpringRunner.class)
public class MainTest {
...
#Test
public void testingSomething(){
PrintForTest.print("My new System.out.print()");
Assert.assertEquals(...);
}
}
edited: using static method, no need to use #Autowired.
This sound familiar to me, so I assume you're running your tests from some IDE (Netbeans?). It might be the case that it only shows the output for tests that fail. Does this also occur when running the test from console?
You might have more luck using System.err instead of System.out, but I'm not sure about this.
I am using gradle. I had this problem with both System.out and java.util.logging.Logger. I edited the following part of my build.gradle file:
test {
testLogging {
exceptionFormat = 'full'
events = ["passed", "failed", "skipped"]
}
}
and added showStandardStreams = true under testLogging. The result was as follows:
test {
testLogging {
exceptionFormat = 'full'
events = ["passed", "failed", "skipped"]
showStandardStreams = true
}
}
It fixed both of them.

How to use JUnit tests with Spring Roo? (Problems with EntityManager)

I'm trying to write a JUnit test for a Spring Roo project. If my test requires use of the entity classes, I get the following Exception:
java.lang.IllegalStateException: Entity manager has not been injected
(is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
The Spring Aspects JAR looks to be configured correctly. In particular, I have the following in the pom.xml file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
and
<plugin>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
and the classes that use the entity classes work fine, when not called from a JUnit test. Any idea how I can set things up so that the Entity manager is injected from a JUnit test?
Here is my Test class (more or less):
public class ServiceExampleTest {
#Test
public void testFoo() {
FooService fs = new FooServiceImpl();
Set<Foo> foos = fs.getFoos();
}
}
This is enough to throw the exception. The FooServiceImpl class returns a Set of Foo, where Foo is an entity class. The getFoos() method works when the application is run in the usual way. The problem only comes in the context of unit tests.
ponzao is correct. I am able to have all the spring injection magic by having my test class extend AbstractJunit4SpringContextTests.
e.g.
#ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" })
public class SelfRegistrationTest extends AbstractJUnit4SpringContextTests {
This is an incredibly annoying problem with Spring Roo and I have not figured out the official solution for.
But ... here are two workarounds:
Copy the spring-aspects jar to your project then add it to your Projects AspectJ Aspect Path
Use Maven to run your unit tests (and miss the green bar :( )
For option one Right click on your project select Properties-> AspectJ Build -> Aspect Path Tab.
Your unit test class should have #MockStaticEntityMethods annotation.
Just wanted to add more detail to the above answer by #migue as it took me a while to figure out how to get it to work. The site http://java.dzone.com/articles/mock-static-methods-using-spring-aspects really helped me to derive the answer below.
Here is what I did to inject entity manager via test class. Firstly annotate your test class with #MockStaticEntityMethods and create MockEntityManager class (which is a class that just implements EntityManager interface).
Then you can do the following in your ServiceExampleTest test class:
#Test
public void testFoo() {
// call the static method that gets called by the method being tested in order to
// "record" it and then set the expected response when it is replayed during the test
Foo.entityManager();
MockEntityManager expectedEntityManager = new MockEntityManager() {
// TODO override what method you need to return whatever object you test needs
};
AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedEntityManager);
FooService fs = new FooServiceImpl();
Set<Foo> foos = fs.getFoos();
}
This means when you called fs.getFoos() the AnnotationDrivenStaticEntityMockingControl will have injected your mock entity manager as Foo.entityManager() is a static method.
Also note that if fs.getFoos() calls other static methods on Entity classes like Foo and Bar, they must also be specified as part of this test case.
So say for example Foo had a static find method called "getAllBars(Long fooId)" which gets called when fs.getFoos() get called, then you would need to do the following in order to make AnnotationDrivenStaticEntityMockingControl work.
#Test
public void testFoo() {
// call the static method that gets called by the method being tested in order to
// "record" it and then set the expected response when it is replayed during the test
Foo.entityManager();
MockEntityManager expectedEntityManager = new MockEntityManager() {
// TODO override what method you need to return whatever object you test needs
};
AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedEntityManager);
// call the static method that gets called by the method being tested in order to
// "record" it and then set the expected response when it is replayed during the test
Long fooId = 1L;
Foo.findAllBars(fooId);
List<Bars> expectedBars = new ArrayList<Bar>();
expectedBars.add(new Bar(1));
expectedBars.add(new Bar(2));
AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedBars);
FooService fs = new FooServiceImpl();
Set<Foo> foos = fs.getFoos();
}
Remember the AnnotationDrivenStaticEntityMockingControl must be in the same order that fs.getFoos() calls its static methods.
Your unit test class should have #MockStaticEntityMethods annotation.
I was also running into the same exception and everything was configured correctly. I removed the project and reimported it again in STS (SpringSource Tool Suite) and this problem went away.
Not sure why this fixed it but this issue could have been caused by use of Eclipse to manage the Roo generated project before switching to STS in my case.
Long time after the question but I have a working solution when trying to run Spring Roo unit tests from within Eclipse...
Have the project open in Eclipse
In Eclipse, Project > Clean > Rebuild (Automatic or Manual doesn't matter)
Once the re-build is complete, in a console window, have Maven clean and re-package (Clean is required):
mvn clean package
or if your unit tests are failing in maven (and you need Eclipse for debugging your tests)
mvn clean package -Dmaven.test.skip=true
4. Once the package is successful, then refresh back in Eclipse.
You should be able to run unit tests successfully back in Eclipse now. I found editing entities caused the greatest frequency of the entity manager error. When I stayed clear of editing them, I could edit other classes and unit tests would continue to run successfully.
This worked for me with Spring Roo:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import com.jitter.finance.analyzer.domain.Address;
#ContextConfiguration(locations = { "classpath*:/META-INF/spring/applicationContext*.xml"})
public class EmTest extends AbstractJUnit4SpringContextTests {
#Test
public void checkEm(){
Address a = new Address();
a.setName("Primo");
a.persist();
Address b = new Address();
b.setName("Secondo");
b.persist();
for(Address ad : Address.findAllAddresses()){
System.out.println(ad.getName());
assertEquals(ad.getName().charAt(ad.getName().length()-1), 'o');
}
}
}
With Address class like this:
import org.springframework.roo.addon.javabean.annotations.RooJavaBean;
import org.springframework.roo.addon.javabean.annotations.RooToString;
import org.springframework.roo.addon.jpa.annotations.activerecord.RooJpaActiveRecord;
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class Address {
private String name;
}

Categories