I am trying to write my own Junit5 test runner using LauncherDiscoveryRequestBuilder, when i use the class selector, I am able to run the test no problem. However, when I try to use the package selector, no test can be discovered.
Here is the code using selectClass that works:
LauncherDiscoveryRequestBuilder requestBuilder = new LauncherDiscoveryRequestBuilder();
requestBuilder.selectors(selectClass("com.abc.myservice.tests.MyTests"));
LauncherDiscoveryRequest request = requestBuilder.build();
Launcher launcher = LauncherFactory.create();
launcher.execute(request);
Here is the code using selectPackage that cannot find any test:
LauncherDiscoveryRequestBuilder requestBuilder = new LauncherDiscoveryRequestBuilder();
requestBuilder.selectors(selectPackage("com.abc.myservice.tests"));
LauncherDiscoveryRequest request = requestBuilder.build();
Launcher launcher = LauncherFactory.create();
launcher.execute(request);
Here is my test code
package com.abc.myservice.tests;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MyTests {
#Test
public void eqTest() {
assertEquals(2, 2);
}
}
Any help would be appreciate!
This might be because your main folder is not in the same context as your tests.
You can add this to your build tag pom.xml file so it will compile your test classes to the same path as the rest of the project classes.
<testOutputDirectory>target/classes</testOutputDirectory>
Here is an example:
<build>
<testOutputDirectory>target/classes</testOutputDirectory>
<plugins>
...
</plugins>
</build>
You won't be able to select your classes directly with
LauncherDiscoveryRequestBuilder.request().selectors(selectClass(my.package.tests.MyClass.class))
But you should not have any problem with the selectPackage method you are using.
There might be other work-arounds that I'm not aware of but this is working for JUnit5 right now.
Related
I have a Spring Boot 2.5.4 project with some #SpringBootTest tests and some #Cucumber tests. I am using gradle to build.
I have noticed that my build is failing depending on where it's executed, and I found that it actually depended on the order the tests get executed, so I have a problem in my tests : if #SpringBootTest runs first then it's passing. if #Cucumber tests run first then it fails - probably because the H2 DB doesn't get fully reset in between.
Now, I would like to temporarily control the execution order, so that I can reproduce the issue consistently to fix the data dependency between my tests.
I am trying to use junit.jupiter.testclass.order.default property with value org.junit.jupiter.api.ClassOrderer$ClassName but it's not working.
I've put my 2 tests in a Juint5 #Suite mentioning the 2 tests in the #SelectClasses and changing their order, but even like that, it's not working - my feeling is that it's because there are actually 2 test runners, Junit Jupiter and Cucumber. Sometimes when I change something that doesn't seem related, the execution order changes :
I'm overriding Junit version to latest, hoping that it helps (and Junit5 Suite is available), but it doesn't help :
ext['junit-jupiter.version']='5.9.2'
I am using Cucumber 6.11.0.
My gradle test task is simply
test {
useJUnitPlatform()
finalizedBy(project.tasks.jacocoTestReport)
}
Is there a way to configure in my build the order in which the test runners get executed, in a consistent and reproduceable manner ?
Thanks
Gradle uses the JUnit Platform Launcher API to run the tests. You can do the same thing. And to ensure the order remains the same, you would invoke the platform twice within the same JVM.
This should allow you to reproduce your problem as Spring keeps the application running until the JVM exits.
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import my.project.spring.MySpringBootTest;
import my.project.cucumber.MyCucumberTest;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
import org.junit.platform.launcher.listeners.TestExecutionSummary;
public class ManualLaunch {
public static void main(String[] args) {
var cucumberSummary= runCucumberTest();
var jupiterSummary= runJupiterTest();
System.out.println("Jupiter failures : "+jupiterSummary.getTestsFailedCount());
System.out.println("Cucumber failures : "+cucumberSummary.getTestsFailedCount());
}
private static TestExecutionSummary runCucumberTest() {
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
// Configure the request for Cucumber here
.selectors(
selectClass(MyCucumberTest.class)
)
.build();
return launchAndGetSummary(request);
}
private static TestExecutionSummary runJupiterTest() {
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(
selectClass(MySpringBootTest.class)
)
.build();
return launchAndGetSummary(request);
}
private static TestExecutionSummary launchAndGetSummary(LauncherDiscoveryRequest request){
Launcher launcher = LauncherFactory.create();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
return listener.getSummary();
}
}
If you don't know how to run a main method from Gradle, you could also use JUnit to run JUnit. But then you do have to make sure the tests don't target themselves.
I have Junit5Runner class which starts Junit5 test programmatically.
It's not a maven project now, it's a simple java project with no any framework.
I need to switch to maven project, but in a maven project test classes are located inside test folder and aren't accessable from src folder.
How can I get access to test class from test folder in the main class from src folder?
Here is my Junit5Runner code.
Here I get access to CalculatorTest class.
public class Junit5Runner {
SummaryGeneratingListener listener = new SummaryGeneratingListener();
public void runOne() {
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(CalculatorTest.class)) //I NEED TO GET THIS CLASS FROM TEST FOLDER
.build();
Launcher launcher = LauncherFactory.create();
TestPlan testPlan = launcher.discover(request);
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
}
public static void main(String[] args) {
final Junit5Runner runner = new Junit5Runner();
runner.runOne();
TestExecutionSummary summary = runner.listener.getSummary();
for (TestExecutionSummary.Failure failure : summary.getFailures()) {
System.out.println(failure.getTestIdentifier().getDisplayName());
System.out.println(failure.getException());
}
}
}
The simplest solution is to put your production code int src/main/java/<package> and your unit tests into src/test/java/<packageName> and name your unit tests like *Test.java. If you follow that you can execute your unit tests (assumed you have added the appropriate dependencies for JUnit Jupiter in your pom file) via
mvn clean test
Full setup for JUnit Jupiter and example project can be found here.
My requirement is to run Cucumber test cases using Spring boot to run through a Custom java main class.
I am able to run Cucumber test suite fine if i am using following config class:-
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {
"html:target/cucumber-html-report",
"json:target/cucumber.json", "pretty:target/cucumber-
pretty.txt",
"usage:target/cucumber-usage.json", "junit:target/cucumber-
results.xml" },
features = { "src/test/resources" },
tags = {"#passed"},
glue = "cucumberTest.steps")
public class RunGwMLCompareTests {
}
And following class to load
#RunWith(SpringRunner.class)
#ActiveProfiles("dev")
#SpringBootTest(classes = Application.class)
public class AbstractDefinitions {
public AbstractDefinitions() {
}
}
And when i run RunGwMLCompareTests class,Now using this config my Cucumber test cases are running , It loads my Spring boot context and then exceutes all cases defined in feature.
Now my issue is that i want to run this from seperate main java class. I have created my java class as follows :-
package cucumberTest;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.io.MultiLoader;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.io.ResourceLoaderClassFinder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CucumberMainTest {
public static void main(String[] args) throws IOException {
ClassLoader classLoader = CucumberMainTest.class.getClassLoader();
ResourceLoader resourceLoader = new MultiLoader(classLoader);
ClassFinder classFinder = new
ResourceLoaderClassFinder(resourceLoader, classLoader);
List<String> pluginList = new ArrayList<>();
pluginList.add("--plugin");
pluginList.add("html:target/cucumber-html-report");
pluginList.add("--plugin");
pluginList.add("json:target/cucumber.json");
RuntimeOptions ro = new RuntimeOptions(pluginList);
ro.getFilters().add("#passed");
ro.getFeaturePaths().add("src/test/resources");
ro.getGlue().add("cucumberTest/steps");
cucumber.runtime.Runtime runtime = new
cucumber.runtime.Runtime(resourceLoader, classFinder, classLoader,
ro);
runtime.run();
}
}
It executes my test cases but does not load my SpringContext, as a result no spring beans are loadedand i get null pointer exception.. Any help is geatly appreciated.
Regards,
Vikram Pathania
One solution i found was to run RunGwMLCompareTests class from outside which handles my Spring context automatically.
So basically i am using gradle to create batch file which does nothing but automatically creates a batch with all relative depencies in my class path and then run following command:
"%JAVA_EXE%" -classpath "%CLASSPATH%" org.junit.runner.JUnitCore
cucumberTest.runners.RunGwMLCompareTests
where,
JAVA_EXE=C:\Program Files\Java\jdk1.7.0_65/bin/java.exe
And CLASSPATH is lib folder where all jars are present.
CLASSPATH=%APP_HOME%\lib\*.jar
Now running this batch i am using
features = { "src/test/resources" } <tag>
to put my feature files outside so that it can edited on the fly.
I hope this helps somebody out there.
by doing this , i am able to run RunGwMLCompareTests class.
Now using this config my Cucumber test cases are running and It also loads my Spring boot context and then exceutes all cases defined in feature.
Regards,
Vikram Pathania
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.
I have to automate a test-suite for a web application which let user connect and sync with their Dropbox account. I am using Java Selenium Webdriver.
Here I have created test classes like this.
Class1.java - Test case to check if connected to Internet.
Class2.java- Test case for sign in with Dropbox
Class3.java- Test case to verify if Dropbox folders are shown on web page.
Now these test classes are supposed to execute in this order.
But when I run the project as JUnit test, it executes these tests in some other order. I don't find any XML file so that I can specify order of execution of these classes.
I also have tried TestNG because I read Here that TestNG provides an attribute "preserve-order".
But It is not working. I don't have much experience with Selenium and Java Webdriver.
So any help would be appreciable.
Thanx in advance.
Peter Niederwieser is right.
In addition you can set the order of the tests to run within the classes (Junit 4.11):
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;
import org.junit.Test;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {
#Test
public void firstTest() {
System.out.println("first");
}
#Test
public void secondTest() {
System.out.println("second");
}
}
Addition to Ittiel's post:
Instead of:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
You can use:
#FixMethodOrder(MethodSorters.JVM)
This way, you don't have to play tricks with your test names. You only have to arrange your tests in the correct order.
This works fine for me. Thanks to Ittiel!
You can use a JUnit test suite:
import org.junit.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({Class1.class, Class2.class, Class3.class})
public class DropboxWorkflow {}
Try this
#Test(dataProvider = "Login", priority = 1)
public void login()
{
//code
}
#Test(dataProvider = "Search", priority = 2)
public void search()
{
//code
}