it-swarm.com.de

Ermitteln Sie den Namen des aktuell ausgeführten Tests in JUnit 4

In JUnit 3 konnte ich den Namen des aktuell laufenden Tests folgendermaßen erhalten:

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

was würde drucken "Aktueller Test ist TestSomething". 

Gibt es eine vordefinierte oder einfache Möglichkeit, dies in JUnit 4 zu tun?

Hintergrund: Natürlich möchte ich nicht nur den Namen des Tests ausdrucken. Ich möchte testspezifische Daten laden, die in einer Ressource mit demselben Namen wie der Test gespeichert sind. Sie wissen, Konvention über Konfiguration und das alles.

218
Dave Ray

JUnit 4.7 fügte diese Funktion hinzu. Es scheint, als würde sie TestName-Rule verwenden. Sieht so aus, als würden Sie den Methodennamen erhalten:

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

JUnit 4.9.x und höher

Seit JUnit 4.9 wurde die TestWatchman -Klasse zugunsten der TestWatcher -Klasse aufgegeben:

@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

Der folgende Ansatz druckt Methodennamen für alle Tests in einer Klasse:

@Rule
public MethodRule watchman = new TestWatchman() {
   public void starting(FrameworkMethod method) {
      System.out.println("Starting test: " + method.getName());
   }
};
104
Duncan Jones

In JUnit 5 gibt es eine TestInfo-Injection, die die Bereitstellung von Test-Metadaten für Testmethoden vereinfacht. Zum Beispiel:

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

Mehr dazu: JUnit 5 Benutzerhandbuch , TestInfo javadoc .

8
Andrii Abramov

Erwägen Sie die Verwendung von SLF4J (Simple Logging Facade für Java) und bieten einige Verbesserungen mit parametrisierten Meldungen. Durch die Kombination von SLF4J mit JUnit 4-Regelimplementierungen können effizientere Testklassen-Protokollierungsverfahren bereitgestellt werden.

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
journeyman

Eine gewundene Möglichkeit besteht darin, einen eigenen Runner zu erstellen, indem Sie org.junit.runners.BlockJUnit4ClassRunner subclassing.

Sie können dann so etwas tun:

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

Dann müssen Sie für jede Testklasse eine Annotation @RunWith (NameAwareRunner.class) hinzufügen. Alternativ können Sie diese Anmerkung in eine Superklasse "Test" setzen, wenn Sie sich nicht jedes Mal daran erinnern wollen. Dies begrenzt natürlich die Auswahl der Läufer, dies kann jedoch akzeptabel sein.

Es kann auch ein wenig Kung-Fu erforderlich sein, um den aktuellen Testnamen aus dem Runner und in Ihr Framework zu holen, aber dies bringt Ihnen zumindest den Namen.

6
chris.f.jones

Versuchen Sie es stattdessen:

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

Die Ausgabe sieht folgendermaßen aus:

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

HINWEIS: DieseDOES NOTfunktioniert nicht, wenn Ihr Test eine Unterklasse von TestCase ist! Der Test läuft, aber der @Rule - Code wird nie ausgeführt.

6
Yavin5

Basierend auf dem vorherigen Kommentar und weiteren Überlegungen habe ich eine Erweiterung von TestWather erstellt, die Sie in Ihren JUnit-Testmethoden verwenden können:

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

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

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

Die Testhelper-Klasse ist die nächste:

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

Genießen!

3
Csaba Tenkes

JUnit 4 verfügt über keinen Standardmechanismus für einen Testfall, um seinen eigenen Namen zu erhalten (einschließlich während des Setups und des Herunterfahrens).

3
cordellcp3
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
jnorris
@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
leojkelav

In JUnit 5 fungiert TestInfo als Drop-In-Ersatz für die TestName-Regel von JUnit 4. 

Aus der Dokumentation: 

TestInfo wird verwendet, um Informationen zum aktuellen Test oder .__ einzugeben. Container in @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll und @AfterAll Methoden.

Um den Methodennamen des aktuell ausgeführten Tests abzurufen, haben Sie zwei Optionen: String TestInfo.getDisplayName() und Method TestInfo.getTestMethod()

Um nur den Namen der aktuellen Testmethode abzurufen, reicht TestInfo.getDisplayName() möglicherweise nicht aus, da der Standardanzeigename der Testmethode methodName(TypeArg1, TypeArg2, ... TypeArg3) lautet.
Das Duplizieren von Methodennamen in @DisplayName("..") ist keine gute Idee. 

Als Alternative können Sie TestInfo.getTestMethod() verwenden, die ein Optional<Method>-Objekt zurückgibt.
Wenn die Abrufmethode innerhalb einer Testmethode verwendet wird, müssen Sie nicht einmal den umschlossenen Wert Optional testen. 

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
davidxxx

Dies erreichen Sie mit Slf4j und 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
Coder

Ich würde vorschlagen, dass Sie den Namen der Testmethode von Ihrem Testdatensatz entkoppeln. Ich würde eine DataLoaderFactory-Klasse modellieren, die die Testdatensätze aus Ihren Ressourcen lädt/zwischenspeichert, und dann in Ihrem Testfall cam eine Schnittstellenmethode aufrufen, die einen Testdatensatz für den Testfall zurückgibt. Wenn die Testdaten an den Namen der Testmethode gebunden sind, wird davon ausgegangen, dass die Testdaten nur einmal verwendet werden können. In den meisten Fällen würde ich vorschlagen, dass dieselben Testdaten in mehreren Tests verwendet werden, um verschiedene Aspekte Ihrer Geschäftslogik zu überprüfen. 

0
emeraldjava