Launching JUnit jupiter tests from inside a main method? - junit

I have a Java class with a main method that I invoke to occasionally run some tests. Specifically, I'm trying to come up with a solution for quickly testing various code snippets that use the AWS SDK to create/read some S3 objects. I'm not really trying to build regular unit/integration tests, and I'm not interested in mocking the S3 code. I'm trying to quickly develop/debug some code using a test framework. I found the following SO question, and the answer about using JUnit5 Jupiter's Launcher and it intrigued me:
How do I run JUnit tests from inside my java application?
So I read the Junit5 chapter on the Launcher API and followed the example code. I came up with something like this:
class S3ManualTest {
public static void main(String[] args) {
LauncherDiscoveryRequest request =
LauncherDiscoveryRequestBuilder
.request()
.selectors(selectPackage("com.xyz.s3util"),
selectClass(S3ManualTest.class),
selectMethod(S3ManualTest.class, "happyPath")
)
.build();
Launcher launcher = LauncherFactory.create();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
launcher.execute(request, listener);
TestExecutionSummary summary = listener.getSummary();
System.out.println("# of containers found: " + summary.getContainersFoundCount());
System.out.println("# of containers skipped: " + summary.getContainersSkippedCount());
System.out.println("# of tests found: " + summary.getTestsFoundCount());
System.out.println("# of tests skipped: " + summary.getTestsSkippedCount());
}
void happyPath() {
assertTrue(true); // Do useful stuff here
}
}
The launcher doesn't find any tests to run, even though I specifically selected the "happyPath" method. I have tried annotating the happyPath() method with #Test, and that seems to work, but it also has the undesired side effect that the method gets executed if I run all tests in that package, either from gradle, or from inside the IDE. Essentially, I want my test methods to be invoked with the JUnit5 framework, but only when I manually run the main method in the class. I was thinking about some custom annotations, or implementing some interface that would get picked up by the test engine, but haven't gone down that route yet. I'm guessing there's some easy way of accomplishing what I'm trying to do. Thanks.

I could only find a work around: disabling the happyPath() test method by default and override it in your program like explained here: https://junit.org/junit5/docs/current/user-guide/#extensions-conditions-deactivation
#Test
#Disabled
void happyPath() {
assertTrue(true); // Do useful stuff here
}
And in your launcher setup, deactivate the DisabledCondition:
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
.request()
.selectors(selectMethod(S3ManualTest.class, "happyPath"))
.configurationParameter(
"junit.jupiter.conditions.deactivate",
"org.junit.*DisabledCondition")
.build();
You may also specify a dedicated switch, if you don't want deactivate DisabledCondition for the entire run:
#Test
#EnabledIf("'true'.equals(junitConfigurationParameter.get('manual'))")
void happyPath() {
assertTrue(true); // Do useful stuff here
}
with
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
...
.configurationParameter("manual", "true")
.build();
The second work-around, if applied to more then a few methods, screams for a dedicated ExecutionCondition extension. See details at https://junit.org/junit5/docs/current/user-guide/#writing-tests-conditional-execution-scripts

Related

Is there a way to share #Before code between tests suite classes?

I am testing a Cordova plugin in Java/Android and I need to initialize my Plugin class and set some state before I run my Tests.
#Before
public void beforeEach() throws Exception {
System.out.println("Creating new Instance ");
PowerMockito.mockStatic(Helpers.class);
PowerMockito.when(Helpers.canUseStorage(any(), any())).thenReturn(true);
MyLogger myLoggerMock = PowerMockito.mock(MyLogger.class);
PowerMockito.doNothing().when(myLoggerMock, "log", anyString());
PowerMockito.whenNew(MyLogger.class).withAnyArguments().thenReturn(myLoggerMock);
this.sut = spy(new FilePicker());
PowerMockito.doNothing().when(this.sut).pick(any(), any());
}
I want to create a Test Suite / Java Class per public function, but I do not want to repeat that code every time.
Is there a way to share that before each between test suites? I have found ClassRule but I think I do not do what I need (or I am understanding it wrong... I am really new in Java)
In Typescript we can share beforeEachfunctions with several suites, and each suite can have their own beforeEach
One possible ways is using inheritance:
Make all test classes extend from one "parent test" class and define a #Before in a parent class.
So it will be called automatically for all the subclasses:
public class ParentTest {
#Before
public void doInitialization() {
....
}
}
public class Test1Class extends ParentClass {
#Test
public void fooTest() {
// doInitialization will be executed before this method
}
#Test
public void barTest() {
// doInitialization will be executed before this method as well
}
}
Two notes:
Note 1
In the code you use sut (subject under test) - this obviously should not be in the parent's doInitialization method, so its possible that Test1Class will also have methods annotated with #Before (read here for information about ordering and so forth)
Then the `sut gets initialized with Spy which is frankly weird IMHO, the Subject Under Test should be a real class that you wrote, but that's beyond the scope of the question, just mentioning it because it can point on mistake.
Note 2
I'm writing it in an an attempt to help because you've said that you're new in Java, this is not strictly related to your question...
While this approach works in general you should be really cautious with PowerMockito. I'm not a PowerMockito expert and try to avoid this type of mocks in my code but in a nutshell the way it manipulates the byte code can clash with other tools. From your code: you can refactor the HelperUtils to be non-static and thus avoid PowerMocking in favor of regular mocking which is faster and much more safe.
As for the Logging - usually you can compromise on it in unit test, if you're using slf4j library you can config it to use "no-op" log for tests, like sending all the logging messages into "nothing", and not-seeing them in the console.

Difference in running Cucumber-JVM vs Cucumber runner(Junit)

I am fairly new to Cucumber. I was experimenting with it by just creating few test features when I noticed the difference when running a single feature vs running the whole suite (from the IntelliJ).
I noticed that when I run single feature it runs using the cucumber-jvm option and in this case, the CucumberConfig(the blank class to define the runner and cucumber options) and the Runner is not utilized. However, when I run the whole suite it runs as a JUnit test and obviously, in this case, the Config class and the runner comes into the picture.
I confirmed this with the following sample code:
#RunWith(CustomRunner.class)
#CucumberOptions()
public class CucumberConfig {
#BeforeClass
public static void beforeClass()
{
System.out.println("This is run before Once: ");
}
#AfterClass
public static void afterClass()
{
System.out.println("This is run after Once: ");
}
}
CustomRunner
public class CustomRunner extends Cucumber {
public CustomRunner(Class clazz) throws InitializationError, IOException {
super(clazz);
System.out.println("I am in the custom runner.");
}
}
Also, I understand that while running as cucumber-junit we can't pass specific feature to run as in cucumber-jvm. Correct me if I am wrong.
My doubt is, is this the default behavior or am I doing something wrong. And, if this is default how can I make cucumber to always use the Config file.
I'll appreciate if someone can provide some insight on this.
When you're using IntelliJ IDEA to run the tests, IDEA will use cucumber.api.Main to run the tests. As such it will ignore CucumberConfig neither will it run #BeforeClass nor #AfterClass, these are only used by the JUnit runner.

Fake JavaFX Platform start

In my project I have a peculiar setup for testing JavaFX components: First there is an Application that starts the component normally through a main method for visual inspection. But then there are subclasses of this Main classes which are the actual JUnit tests.
In the tests I do not want to run the application with the UI showing up (the tests should also be runnable in a system that has no window manager, e.g. cuntinuous integration). Normally this will throw an error, as the platform is not started. To prevent this, I call:
final Runnable dummyRunnable = new Runnable() {
#Override
public void run() {
System.out.println("Startup platform");
}
};
PlatformImpl.startup(dummyRunnable);
PlatformImpl however is internal API (com.sun.javafx.application.PlatformImpl). Which basically ties the test to a specific brand of JDK.
To figure out if this happens I actually call the method through reflection, so I can log the specific error cases.
Is there a way to reach the same thing (running the tests which are a subclass of Application, but do not call the start method, to run in headless mode)?

swing uncaughtexceptionhandler

I am trying to build a general exception handler for a swing application as described here: http://www.javaspecialists.eu/archive/Issue081.html
I work in jython (python syntax getting compiled to java and executed). My code looks roughly like this (updated):
def launcher(func):
class launcherThread(Runnable):
def __init__(self):
super(launcherThread, self).__init__()
def run(self):
func()
#trying to get the name which can be used to instantiate this in java
cls = ExceptionGroup().getClass()
fullName = cls.__module__ + '.' + cls.__name__
System.setProperty("sun.awt.exception.handler", fullName)
Thread(ExceptionGroup(), launcherThread(), 'Cross ExceptionHandlerThread').start()
class ExceptionGroup(ThreadGroup):
def __init__(self):
super(ExceptionGroup, self).__init__("HardenedGroup")
def uncaughtException(self, thread, exception):
#make a fancy dialog displaying str(exception)
If I test it it works fine however in the production enviornment it failes.
For testing I launch my program in Eclipse (PyDev), the production enviornment is a third party application written in Java, that has a Jython console build in. The application supports adding of custom menu entries, and putting jython scripts on these.
The main difference I see between testing and production enviornment is that in the production enviornment the swing threads are allready started (the third party application utilitizes swing). Does this cause my ThreadGroup setting to fail, or is there another reason why this is not working?
How can I get the Involved threads (exceptions ar thrown as a result of buttonActions) to check their defaultException handlers? If (as I am afraid) it should turn out that the third party installed its own handler (all exceptions are written to a log file) how can I make a new swing worker thread? (I don't want to catch the exceptions created by the host application after all)
Question recap:
1. How can I check which threads are started for the function func passed into the launcher function and see thier uncaught exception handler?
2. Can I enforce a seperate swing dispatcher for my gui part and the main applications gui part? (If I exitOnClos on a frame of my add in, the third party application closes)?
Update:
Considering the anwser from lbalazscs I am trying to use the sun.awt.exception.handler property, but it has no effect, the exceptions still end up in the log file (applications dfeault behaviour). Am I using it right? (p.s.: I am on Java 1.6)
If you have Java 5 or higher, you can also use Thread.setDefaultUncaughtExceptionHandler(), which is also described in a newer "Java Specialists' Newsletter":
http://www.javaspecialists.eu/archive/Issue089.html
And here is the newest Java 7 version:
http://www.javaspecialists.eu/archive/Issue196.html
Also see this:
Why bother with setting the "sun.awt.exception.handler" property?
EDIT: This is how I use Thread.setDefaultUncaughtExceptionHandler (in Java...):
public static void setupGlobalExceptionHandling() {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
handleException(e);
}
});
}

Globally setting a JUnit runner instead of #RunWith

Without looking into JUnit source itself (my next step) is there an easy way to set the default Runner to be used with every test without having to set #RunWith on every test? We've got a huge pile of unit tests, and I want to be able to add some support across the board without having to change every file.
Ideally I'm hope for something like: -Djunit.runner="com.example.foo".
I don't think this is possible to define globally, but if writing you own main function is an option, you can do something similar through code. You can create a custom RunnerBuilder and pass it to a Suite together with your test classes.
Class<?>[] testClasses = { TestFoo.class, TestBar.class, ... };
RunnerBuilder runnerBuilder = new RunnerBuilder() {
#Override
public Runner runnerForClass(Class<?> testClass) throws Throwable {
return new MyCustomRunner(testClass);
}
};
new JUnitCore().run(new Suite(runnerBuilder, testClasses));
This won't integrate with UI test runners like the one in Eclipse, but for some automated testing scenarios it could be an option.
JUnit doesn’t supporting setting the runner globally. You can hide away the #RunWith in a base class, but this probably won't help in your situation.
Depending on what you want to achieve, you might be able to influence the test behavior globally by using a custom RunListener. Here is how to configure it with the Maven Surefire plugin: http://maven.apache.org/plugins/maven-surefire-plugin/examples/junit.html#Using_custom_listeners_and_reporters