Pobierz nazwę aktualnie wykonywanego testu w JUnit 4

W JUnit 3, mogłem uzyskać nazwę aktualnie uruchomionego testu tak:

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

, który drukuje "bieżący test to test czegoś".

Czy Jest jakiś prosty sposób, aby to zrobić w JUnit 4?

Tło: oczywiście, nie chcę po prostu drukować nazwy testu. Chcę załadować dane specyficzne dla testu, które są przechowywane w zasobie o tej samej nazwie co test. Wiesz, konwencja nad konfiguracją i tak dalej.

Dzięki!
Author: Dave Ray, 2009-01-23

13 answers

JUnit 4.7 dodał tę funkcję używając Testname-Rule . Wygląda na to, że to da Ci nazwę metody:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-29 08:24:49

JUnit 4.9.x i wyżej

Od JUnit 4.9,TestWatchman klasa została zdeprecjonowana na rzecz TestWatcher klasa, która ma inwokację:

@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

Następujące podejście wyświetli nazwy metod dla wszystkich testów w klasie:

@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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-15 18:20:24

Rozważ użycie SLF4J (Simple Logging for Java) zapewnia pewne ulepszenia przy użyciu sparametryzowanych komunikatów. Połączenie SLF4J z implementacjami reguł JUnit 4 może zapewnić bardziej wydajne techniki rejestrowania klas testowych.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-29 10:25:08

Zawiłym sposobem jest stworzenie własnego biegacza poprzez podklasowanie org.junit.biegacze.BlockJUnit4ClassRunner.

Możesz wtedy zrobić coś takiego:

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);
    }
}

Następnie dla każdej klasy testowej musisz dodać @RunWith (NameAwareRunner.Klasa) Przypisy Alternatywnie, możesz umieścić tę adnotację na superklasie testowej, jeśli nie chcesz pamiętać jej za każdym razem. To oczywiście ogranicza wybór biegaczy, ale może to być dopuszczalne.

Również, może to trochę potrwać z kung fu, aby uzyskać obecną nazwę testu z biegacza i do swoich RAM, ale to przynajmniej dostaje nazwę.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-16 21:45:02

Spróbuj zamiast tego:

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());
        }
}

Wyjście wygląda tak:

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

Uwaga: to Nie pracuj, jeśli twój test jest podklasą TestCase! Test działa, ale kod @Rule Nigdy nie działa.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-19 21:17:43

W JUnit 5 znajduje się TestInfo iniekcja, która upraszcza podawanie metadanych testowych metodom testowym. Na przykład:

@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"));
}

Zobacz więcej: JUnit 5 podręcznik użytkownika, 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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-01 08:24:51

JUnit 4 nie posiada gotowego do użycia mechanizmu pozwalającego na uzyskanie własnej nazwy przez przypadek testowy (w tym podczas konfiguracji i tearddown).

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-23 15:57:44

Na podstawie poprzedniego komentarza i dalszego rozważenia stworzyłem rozszerzenie Testwather, które można wykorzystać w swoich metodach testowych JUnit z tym:

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

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

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

Klasa pomocnicza testu jest następna:

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());
}
}
Smacznego!
 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-12 13:13:04

Sugerowałbym oddzielenie nazwy metody testowej od zestawu danych testowych. Modelowałbym klasę DataLoaderFactory, która ładuje / buforuje zestawy danych testowych z Twoich zasobów, a następnie w Twoim przypadku testowym cam wywołał jakąś metodę interfejsu, która zwraca zestaw danych testowych dla przypadku testowego. Posiadanie danych testowych związanych z nazwą metody testowej zakłada, że dane testowe mogą być używane tylko raz, gdzie w większości przypadków sugerowałbym, że te same dane testowe w zastosowaniach w wielu testach w celu weryfikacji różnych aspektów twoja logika biznesowa.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 21:03:40

Można to osiągnąć za pomocą Slf4j i 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-14 04:52:58

W JUnit 5 TestInfo działa jako zamiennik reguły TestName z JUnit 4.

Z dokumentacji:

TestInfo służy do wprowadzania informacji o bieżącym teście lub kontener do @Test, @ RepeatedTest, @Parametryzedtest, @TestFactory, @ BeforeEach, @AfterEach, @BeforeAll i @AfterAll metody.

Aby pobrać nazwę metody bieżącego wykonanego testu, masz dwie opcje: String TestInfo.getDisplayName() i Method TestInfo.getTestMethod().

Pobranie tylko nazwy bieżącej metody testowej TestInfo.getDisplayName() może nie wystarczyć, ponieważ domyślna nazwa metody testowej to methodName(TypeArg1, TypeArg2, ... TypeArg3).
Powielanie nazw metod w @DisplayName("..") nie jest konieczne dobrym pomysłem.

Jako alternatywę możesz użyć TestInfo.getTestMethod(), który zwraca Optional<Method> obiekt.
Jeśli metoda pobierania jest używana wewnątrz metody testowej, nie trzeba nawet testować wartości Optional owiniętej.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-12 16:09:36