org.testfx.framework.junit5.JavaFXInterceptorUtils Maven / Gradle / Ivy
/*
* Copyright 2013-2014 SmartBear Software
* Copyright 2014-2023 The TestFX Contributors
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the
* European Commission - subsequent versions of the EUPL (the "Licence"); You may
* not use this work except in compliance with the Licence.
*
* You may obtain a copy of the Licence at:
* http://ec.europa.eu/idabc/eupl.html
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the Licence for the
* specific language governing permissions and limitations under the Licence.
*/
package org.testfx.framework.junit5;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.testfx.framework.junit5.utils.FXUtils;
/**
* Simple JUnit 5 extension to ensure that {@code @Test} statements are executed
* in the JavaFX UI thread. This is (strictly) necessary when testing setter
* and/or getter methods of JavaFX classes (ie. Node derived, properties etc).
*
* Use the
*
* - {@code @ExtendWith(avaFxInterceptor.class) } if all @Test, or
*
- {@code @ExtendWith(SelectiveJavaFxInterceptor.class) } if only @Test
* + @TestFx annotated tests
*
* should be executed within the JavaFX UI thread.
*/
public class JavaFXInterceptorUtils {
/**
* Simple JUnit 5 extension to ensure that {@code @Test} statements are executed
* in the JavaFX UI thread. This is (strictly) necessary when testing setter
* and/or getter methods of JavaFX classes (ie. Node derived, properties etc).
*
* Example usage:
*
*
*
* @ExtendWith(ApplicationExtension.class)
* @ExtendWith(JavaFxInterceptor.class)
* public class SquareButtonTest {
* @Start
* public void start(Stage stage) {
* // usual FX initialisation
* // ...
* }
*
* @TestFx
* // note: this is equivalent to {@code @Test} when using {@code @ExtendWith(JavaFxInterceptor.class)}
* public void testJavaFxThreadSafety() {
* // verifies that this test is indeed executed in the JavaFX thread
* assertTrue(Platform.isFxApplicationThread());
*
* // perform the regular JavaFX thread safe assertion tests
* // ...
* }
*
* @Test // also executed in JavaFX thread,
* // for different behaviour use: {@code @ExtendWith(SelectiveJavaFxInterceptor.class)}
* public void testNonJavaFx() {
* // verifies that this test is also executed in the JavaFX thread
* assertTrue(Platform.isFxApplicationThread());
*
* // perform regular assertion tests within the JavaFX thread
* // ...
* }
* }
*
*
*
*/
public static class JavaFxInterceptor implements InvocationInterceptor {
@Override
public void interceptTestMethod(final Invocation invocation,
final ReflectiveInvocationContext invocationContext,
final ExtensionContext extensionContext) throws Throwable {
final AtomicReference throwable = new AtomicReference<>();
// N.B. explicit run and wait since the test should only continue
// if the previous JavaFX access as been finished.
FXUtils.runAndWait(() -> {
try {
// executes function after @Test
invocation.proceed();
}
catch (final Throwable t) {
throwable.set(t);
}
});
final Throwable t = throwable.get();
if (t != null) {
throw t;
}
}
}
/**
* Simple JUnit 5 extension to ensure that {@code @Test} statements are executed
* in the JavaFX UI thread. This is (strictly) necessary when testing setter
* and/or getter methods of JavaFX classes (ie. Node derived, properties etc).
*
* Example usage:
*
*
*
* @ExtendWith(ApplicationExtension.class)
* @ExtendWith(SelectiveJavaFxInterceptor.class)
* public class SquareButtonTest {
* @Start
* public void start(Stage stage) {
* // usual FX initialisation
* // ...
* }
*
* @TestFx // forces execution in JavaFX thread
* public void testJavaFxThreadSafety() {
* // verifies that this test is indeed executed in the JavaFX thread
* assertTrue(Platform.isFxApplicationThread());
*
* // perform the regular JavaFX thread safe assertion tests
* // ...
* }
*
* @Test // explicitly not executed in JavaFX thread;
* // for different behaviour use: {@code @ExtendWith(JavaFxInterceptor.class)}
* public void testNonJavaFx() {
* // verifies that this test is not executed within the JavaFX thread
* assertFalse(Platform.isFxApplicationThread());
*
* // perform the regular non-JavaFX thread-related assertion tests
* // ...
* }
* }
*
*
*
*/
public static class SelectiveJavaFxInterceptor implements InvocationInterceptor {
@Override
public void interceptTestMethod(final Invocation invocation,
final ReflectiveInvocationContext invocationContext,
final ExtensionContext extensionContext) throws Throwable {
final AtomicReference throwable = new AtomicReference<>();
boolean isFxAnnotation = false;
final Optional element = extensionContext.getElement();
if (element.isPresent()) {
for (final Annotation annotation : element.get().getAnnotations()) {
if (annotation.annotationType().equals(TestFx.class)) {
isFxAnnotation = true;
}
}
}
final Runnable testToBeExecuted = () -> {
try {
// executes function after @Test
invocation.proceed();
}
catch (final Throwable t) {
throwable.set(t);
}
};
// N.B. explicit run and wait since the test should only continue
// if the previous JavaFX access as been finished.
if (isFxAnnotation) {
FXUtils.runAndWait(testToBeExecuted);
} else {
testToBeExecuted.run();
}
final Throwable t = throwable.get();
if (t != null) {
throw t;
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy