Obtener el nombre de la prueba actualmente en ejecución en JUnit 4


En JUnit 3, podría obtener el nombre de la prueba actualmente en ejecución de esta manera:

public class MyTest extends TestCase
{
    public void testSomething()
    {
        System.out.println("Current test is " + getName());
        ...
    }
}

Que imprimiría "Prueba actual es testSomething".

¿Hay alguna forma sencilla o lista para usar de hacer esto en JUnit 4?

Antecedentes: Obviamente, no quiero simplemente imprimir el nombre de la prueba. Quiero cargar datos específicos de la prueba que se almacenan en un recurso con el mismo nombre que la prueba. Ya sabes, convención sobre configuración y todo eso.

Gracias!

Author: Dave Ray, 2009-01-23

13 answers

JUnit 4.7 agregó esta característica que parece usar TestName-Rule. Parece que esto te dará el nombre del método:

import org.junit.Rule;

public class NameRuleTest {
    @Rule public TestName name = new TestName();

    @Test public void testA() {
        assertEquals("testA", name.getMethodName());
    }

    @Test public void testB() {
        assertEquals("testB", name.getMethodName());
    }
}
 334
Author: FroMage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-29 08:24:49

JUnit 4.9.x y superiores

Desde JUnit 4.9, el TestWatchman clase ha sido desaprobada en favor de la TestWatcher clase, que tiene invocación:

@Rule
public TestRule watcher = new TestWatcher() {
   protected void starting(Description description) {
      System.out.println("Starting test: " + description.getMethodName());
   }
};

JUnit 4.7.x - 4.8.x

El siguiente enfoque imprimirá los nombres de los métodos para todas las pruebas de una clase:

@Rule
public MethodRule watchman = new TestWatchman() {
   public void starting(FrameworkMethod method) {
      System.out.println("Starting test: " + method.getName());
   }
};
 99
Author: Duncan Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-15 18:20:24

Considere usar SLF4J (Simple Logging Facade for Java) proporciona algunas mejoras ordenadas usando mensajes parametrizados. La combinación de SLF4J con implementaciones de reglas JUnit 4 puede proporcionar técnicas de registro de clases de prueba más eficientes.

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingTest {

  @Rule public MethodRule watchman = new TestWatchman() {
    public void starting(FrameworkMethod method) {
      logger.info("{} being run...", method.getName());
    }
  };

  final Logger logger =
    LoggerFactory.getLogger(LoggingTest.class);

  @Test
  public void testA() {

  }

  @Test
  public void testB() {

  }
}
 7
Author: journeyman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-29 10:25:08

Una forma complicada es crear tu propio Corredor mediante la subclase org.junit.corredor.BlockJUnit4ClassRunner.

Entonces puedes hacer algo como esto:

public class NameAwareRunner extends BlockJUnit4ClassRunner {

    public NameAwareRunner(Class<?> aClass) throws InitializationError {
        super(aClass);
    }

    @Override
    protected Statement methodBlock(FrameworkMethod frameworkMethod) {
        System.err.println(frameworkMethod.getName());
        return super.methodBlock(frameworkMethod);
    }
}

Luego, para cada clase de prueba, necesitará agregar un @RunWith(NameAwareRunner.class) anotación. Alternativamente, puedes poner esa anotación en una superclase de prueba si no quieres recordarla cada vez. Esto, por supuesto, limita su selección de corredores, pero eso puede ser aceptable.

También, puede tomar un poco de kung fu para obtener el nombre de prueba actual fuera del Corredor y en su marco, pero esto al menos te da el nombre.

 6
Author: chris.f.jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-16 21:45:02

Prueba esto en su lugar:

public class MyTest {
        @Rule
        public TestName testName = new TestName();

        @Rule
        public TestWatcher testWatcher = new TestWatcher() {
            @Override
            protected void starting(final Description description) {
                String methodName = description.getMethodName();
                String className = description.getClassName();
                className = className.substring(className.lastIndexOf('.') + 1);
                System.err.println("Starting JUnit-test: " + className + " " + methodName);
            }
        };

        @Test
        public void testA() {
                assertEquals("testA", testName.getMethodName());
        }

        @Test
        public void testB() {
                assertEquals("testB", testName.getMethodName());
        }
}

La salida se ve así:

Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB

NOTA: Esto NO LO HACE ¡trabaja si tu prueba es una subclase de TestCase ! La prueba se ejecuta, pero el código @Rule simplemente nunca se ejecuta.

 6
Author: Yavin5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-19 21:17:43

En JUnit 5 hay TestInfo inyección que simplifica los metadatos de prueba proporcionando a los métodos de prueba. Por ejemplo:

@Test
@DisplayName("This is my test")
@Tag("It is my tag")
void test1(TestInfo testInfo) {
    assertEquals("This is my test", testInfo.getDisplayName());
    assertTrue(testInfo.getTags().contains("It is my tag"));
}

Ver más: Guía de usuario de JUnit 5, TestInfo javadoc .

 6
Author: Andrii Abramov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-01 08:24:51

JUnit 4 no tiene ningún mecanismo listo para usar para que un caso de prueba obtenga su propio nombre (incluso durante la configuración y el desmontaje).

 4
Author: cordellcp3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-23 15:57:44

Basado en el comentario anterior y considerando aún más, creé una extensión de TestWather que puede usar en sus métodos de prueba JUnit con esto:

public class ImportUtilsTest {
    private static final Logger LOGGER = Logger.getLogger(ImportUtilsTest.class);

    @Rule
    public TestWatcher testWatcher = new JUnitHelper(LOGGER);

    @Test
    public test1(){
    ...
    }
}

La clase test helper es la siguiente:

public class JUnitHelper extends TestWatcher {
private Logger LOGGER;

public JUnitHelper(Logger LOGGER) {
    this.LOGGER = LOGGER;
}

@Override
protected void starting(final Description description) {
    LOGGER.info("STARTED " + description.getMethodName());
}

@Override
protected void succeeded(Description description) {
    LOGGER.info("SUCCESSFUL " + description.getMethodName());
}

@Override
protected void failed(Throwable e, Description description) {
    LOGGER.error("FAILURE " + description.getMethodName());
}
}

Disfrute!

 3
Author: Csaba Tenkes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 01:19:09
String testName = null;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for (int i = trace.length - 1; i > 0; --i) {
    StackTraceElement ste = trace[i];
    try {
        Class<?> cls = Class.forName(ste.getClassName());
        Method method = cls.getDeclaredMethod(ste.getMethodName());
        Test annotation = method.getAnnotation(Test.class);
        if (annotation != null) {
            testName = ste.getClassName() + "." + ste.getMethodName();
            break;
        }
    } catch (ClassNotFoundException e) {
    } catch (NoSuchMethodException e) {
    } catch (SecurityException e) {
    }
}
 2
Author: jnorris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-30 23:05:05
@ClassRule
public static TestRule watchman = new TestWatcher() {
    @Override
    protected void starting( final Description description ) {
        String mN = description.getMethodName();
        if ( mN == null ) {
            mN = "setUpBeforeClass..";
        }

        final String s = StringTools.toString( "starting..JUnit-Test: %s.%s", description.getClassName(), mN );
        System.err.println( s );
    }
};
 1
Author: leojkelav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-12 13:13:04

Le sugiero que desacople el nombre del método de prueba de su conjunto de datos de prueba. Modelaría una clase DataLoaderFactory que carga / almacena en caché los conjuntos de datos de prueba de sus recursos, y luego en su caso de prueba cam llame a algún método de interfaz que devuelve un conjunto de datos de prueba para el caso de prueba. Tener los datos de prueba vinculados al nombre del método de prueba supone que los datos de prueba solo se pueden usar una vez, donde en la mayoría de los casos sugeriría que los mismos datos de prueba en usos en múltiples pruebas para verificar varios aspectos de tu lógica de negocios.

 0
Author: emeraldjava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-24 21:03:40

Puede lograr esto usando Slf4j y TestWatcher

private static Logger _log = LoggerFactory.getLogger(SampleTest.class.getName());

@Rule
public TestWatcher watchman = new TestWatcher() {
    @Override
    public void starting(final Description method) {
        _log.info("being run..." + method.getMethodName());
    }
};
 0
Author: Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-14 04:52:58

En JUnit 5 TestInfo actúa como un reemplazo drop-in para la regla TestName de JUnit 4.

De la documentación:

TestInfo se utiliza para inyectar información sobre la prueba actual o contenedor en to @Test, @ RepeatedTest, @ParameterizedTest, @TestFactory, @beforeEach, @afterEach, @beforeAll y @AfterAll método.

Para recuperar el nombre del método de la prueba ejecutada actual, tiene dos opciones: String TestInfo.getDisplayName() y Method TestInfo.getTestMethod().

Recuperar solo el nombre del método de ensayo actual TestInfo.getDisplayName() puede no ser suficiente, ya que el nombre para mostrar predeterminado del método de ensayo es methodName(TypeArg1, TypeArg2, ... TypeArg3).
Duplicar nombres de métodos en @DisplayName("..") no es una buena idea.

Como alternativa podría utilizar TestInfo.getTestMethod() que devuelve un objeto Optional<Method>.
Si el método de recuperación se utiliza dentro de un método de prueba, ni siquiera necesita probar el valor envuelto Optional.

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;

@Test
void doThat(TestInfo testInfo) throws Exception {
    Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
    Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}
 0
Author: davidxxx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-12 16:09:36