All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.junit.jupiter.api.MethodOrderer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015-2020 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * https://www.eclipse.org/legal/epl-v20.html
 */

package org.junit.jupiter.api;

import static java.util.Comparator.comparingInt;
import static org.apiguardian.api.API.Status.DEPRECATED;
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
import static org.apiguardian.api.API.Status.STABLE;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;

import org.apiguardian.api.API;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.ClassUtils;

/**
 * {@code MethodOrderer} defines the API for ordering the test methods
 * in a given test class.
 *
 * 

In this context, the term "test method" refers to any method annotated with * {@code @Test}, {@code @RepeatedTest}, {@code @ParameterizedTest}, * {@code @TestFactory}, or {@code @TestTemplate}. * *

Built-in Implementations

* *

JUnit Jupiter provides the following built-in {@code MethodOrderer} * implementations. * *

    *
  • {@link MethodName}
  • *
  • {@link OrderAnnotation}
  • *
  • {@link Random}
  • *
* * @since 5.4 * @see TestMethodOrder * @see MethodOrdererContext * @see #orderMethods(MethodOrdererContext) */ @API(status = STABLE, since = "5.7") public interface MethodOrderer { /** * Order the methods encapsulated in the supplied {@link MethodOrdererContext}. * *

The methods to order or sort are made indirectly available via * {@link MethodOrdererContext#getMethodDescriptors()}. Since this method * has a {@code void} return type, the list of method descriptors must be * modified directly. * *

For example, a simplified implementation of the {@link Random} * {@code MethodOrderer} might look like the following. * *

	 * public void orderMethods(MethodOrdererContext context) {
	 *     Collections.shuffle(context.getMethodDescriptors());
	 * }
	 * 
* * @param context the {@code MethodOrdererContext} containing the * {@link MethodDescriptor method descriptors} to order; never {@code null} * @see #getDefaultExecutionMode() */ void orderMethods(MethodOrdererContext context); /** * Get the default {@link ExecutionMode} for the test class * configured with this {@link MethodOrderer}. * *

This method is guaranteed to be invoked after * {@link #orderMethods(MethodOrdererContext)} which allows implementations * of this method to determine the appropriate return value programmatically, * potentially based on actions that were taken in {@code orderMethods()}. * *

Defaults to {@link ExecutionMode#SAME_THREAD SAME_THREAD}, since * ordered methods are typically sorted in a fashion that would conflict * with concurrent execution. * *

In case the ordering does not conflict with concurrent execution, * implementations should return an empty {@link Optional} to signal that * the engine should decide which execution mode to use. * *

Can be overridden via an explicit * {@link org.junit.jupiter.api.parallel.Execution @Execution} declaration * on the test class or in concrete implementations of the * {@code MethodOrderer} API. * * @return the default {@code ExecutionMode}; never {@code null} but * potentially empty * @see #orderMethods(MethodOrdererContext) */ default Optional getDefaultExecutionMode() { return Optional.of(ExecutionMode.SAME_THREAD); } /** * {@code MethodOrderer} that sorts methods alphanumerically based on their * names using {@link String#compareTo(String)}. * *

If two methods have the same name, {@code String} representations of * their formal parameter lists will be used as a fallback for comparing the * methods.

*

This class has been deprecated in favor of * {@link MethodOrderer.MethodName} and will be removed in 6.0

* * @since 5.4 * @deprecated Please use {@link MethodOrderer.MethodName} instead. */ @API(status = DEPRECATED, since = "5.7") @Deprecated class Alphanumeric extends MethodName { } /** * {@code MethodOrderer} that sorts methods alphanumerically based on their * names using {@link String#compareTo(String)}. * *

If two methods have the same name, {@code String} representations of * their formal parameter lists will be used as a fallback for comparing the * methods. * @since 5.7 */ @API(status = EXPERIMENTAL, since = "5.7") class MethodName implements MethodOrderer { /** * Sort the methods encapsulated in the supplied * {@link MethodOrdererContext} alphanumerically based on their names * and formal parameter lists. */ @Override public void orderMethods(MethodOrdererContext context) { context.getMethodDescriptors().sort(comparator); } private static final Comparator comparator = Comparator. // comparing(descriptor -> descriptor.getMethod().getName())// .thenComparing(descriptor -> parameterList(descriptor.getMethod())); private static String parameterList(Method method) { return ClassUtils.nullSafeToString(method.getParameterTypes()); } } /** * {@code MethodOrderer} that sorts methods alphanumerically based on their * display names using {@link String#compareTo(String)} * * @since 5.7 */ @API(status = EXPERIMENTAL, since = "5.7") class DisplayName implements MethodOrderer { /** * Sort the methods encapsulated in the supplied * {@link MethodOrdererContext} alphanumerically based on their display * names. */ @Override public void orderMethods(MethodOrdererContext context) { context.getMethodDescriptors().sort(comparator); } private static final Comparator comparator = Comparator.comparing( MethodDescriptor::getDisplayName); } /** * {@code MethodOrderer} that sorts methods based on the {@link Order @Order} * annotation. * *

Any methods that are assigned the same order value will be sorted * arbitrarily adjacent to each other. * *

Any methods not annotated with {@code @Order} will be assigned the * {@link org.junit.jupiter.api.Order#DEFAULT default order} value which will * effectively cause them to appear at the end of the sorted list, unless * certain methods are assigned an explicit order value greater than the default * order value. Any methods assigned an explicit order value greater than the * default order value will appear after non-annotated methods in the sorted * list. */ class OrderAnnotation implements MethodOrderer { /** * Sort the methods encapsulated in the supplied * {@link MethodOrdererContext} based on the {@link Order @Order} * annotation. */ @Override public void orderMethods(MethodOrdererContext context) { context.getMethodDescriptors().sort(comparingInt(OrderAnnotation::getOrder)); } private static int getOrder(MethodDescriptor descriptor) { return descriptor.findAnnotation(Order.class).map(Order::value).orElse(Order.DEFAULT); } } /** * {@code MethodOrderer} that orders methods pseudo-randomly. * *

Custom Seed

* *

By default, the random seed used for ordering methods is the * value returned by {@link System#nanoTime()} during static initialization * of this class. In order to support repeatable builds, the value of the * default random seed is logged at {@code INFO} level. In addition, a * custom seed (potentially the default seed from the previous test plan * execution) may be specified via the {@link Random#RANDOM_SEED_PROPERTY_NAME * junit.jupiter.execution.order.random.seed} configuration parameter * which can be supplied via the {@code Launcher} API, build tools (e.g., * Gradle and Maven), a JVM system property, or the JUnit Platform configuration * file (i.e., a file named {@code junit-platform.properties} in the root of * the class path). Consult the User Guide for further information. * * @see Random#RANDOM_SEED_PROPERTY_NAME * @see java.util.Random */ class Random implements MethodOrderer { private static final Logger logger = LoggerFactory.getLogger(Random.class); /** * Default seed, which is generated during initialization of this class * via {@link System#nanoTime()} for reproducibility of tests. */ private static final long DEFAULT_SEED; static { DEFAULT_SEED = System.nanoTime(); logger.info(() -> "MethodOrderer.Random default seed: " + DEFAULT_SEED); } /** * Property name used to set the random seed used by this * {@code MethodOrderer}: {@value} * *

Supported Values

* *

Supported values include any string that can be converted to a * {@link Long} via {@link Long#valueOf(String)}. * *

If not specified or if the specified value cannot be converted to * a {@link Long}, the default random seed will be used (see the * {@linkplain Random class-level Javadoc} for details). */ public static final String RANDOM_SEED_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed"; /** * Order the methods encapsulated in the supplied * {@link MethodOrdererContext} pseudo-randomly. */ @Override public void orderMethods(MethodOrdererContext context) { Collections.shuffle(context.getMethodDescriptors(), new java.util.Random(getCustomSeed(context).orElse(DEFAULT_SEED))); } private Optional getCustomSeed(MethodOrdererContext context) { return context.getConfigurationParameter(RANDOM_SEED_PROPERTY_NAME).map(configurationParameter -> { Long seed = null; try { seed = Long.valueOf(configurationParameter); logger.config( () -> String.format("Using custom seed for configuration parameter [%s] with value [%s].", RANDOM_SEED_PROPERTY_NAME, configurationParameter)); } catch (NumberFormatException ex) { logger.warn(ex, () -> String.format( "Failed to convert configuration parameter [%s] with value [%s] to a long. " + "Using default seed [%s] as fallback.", RANDOM_SEED_PROPERTY_NAME, configurationParameter, DEFAULT_SEED)); } return seed; }); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy