[JAVA] JUnit Teststart versuchen Sie etwas

JUnit Teststart versuchen Sie etwas

Informationen zur von Junit verwendeten @ Test-Annotation Die Methode, die diese Annotation implementiert, wird als Testmethode aufgerufen. Ich habe mich gefragt, was für ein Prinzip es funktioniert Betrachten wir den Inhalt der Implementierung

Starten Sie die Junit-Testmethode

Wird die von Junit gestartete Java-Datei zunächst nur die Java-Datei gestartet, die in einem bestimmten Verzeichnis angegeben ist? Wenn Sie beispielsweise eine Java-Datei unter den Einstellungsordner legen, z. B. "src / test" Starten Sie den Test ausgehend von diesem src / test.

Mit anderen Worten, es wird angenommen, dass der Untergebene von src / test als Einstiegspunkt festgelegt ist Durchlaufen Sie die Java-Dateien (Klassendateien) in diesem Verzeichnis Ich glaube, ich führe nur eine Methode aus, für die die Annotation @Test festgelegt ist (Ich kann nicht sicher sagen, weil ich die Implementierung von Junit nicht gesehen habe)

Der Grund, warum der Einstiegspunkt unter einem bestimmten Ordner wie diesem festgelegt ist Abhängig von der Klassenpfadeinstellung werden Java-Dateien in der Reihenfolge aus dem Stammpfad des Klassenladeprogramms gelesen. Suchen Sie nach der Methode mit der Annotation @Test Wenn mit Anmerkungen versehen, instanziieren Sie die Zielklasse Ich dachte, ich würde die Methode ausführen.

Basierend auf dieser Überlegung habe ich versucht zu sehen, ob eine ähnliche Implementierung durch Reflexion erreicht werden kann.

Annotation erstellen

Erstellen Sie eine Annotation für die Methode, z. B. die Annotation @Test

package anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnno {
  boolean testFlg() default false;
}

Diesmal wurde nur die Methode in testFlg auf true gesetzt Implementiert als Ziel des Methodenaufrufs

Erstellen eines Einstiegspunkts für den Start

Ich habe mit @TestAnno nach Klassen und Methoden gesucht und eine Klasse erstellt, die eingeladen werden würde.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

import anno.TestAnno;


public class Entry {

  public static void main(String[] args) throws Exception {

    // *1
    final String resourceName = "test";
    final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    final URL testRoot = classLoader.getResource(resourceName);
    final String appRootStr = classLoader.getResource(".").getFile().toString();



  // *2
    try (Stream<Path> paths = Files.walk(Paths.get(testRoot.toURI()))) {

      paths.filter(Files::isRegularFile).forEach(path -> {


        // *3
        String targertAbsolutePath = path.normalize().toFile().getAbsolutePath().toString();
        String targetClassName = targertAbsolutePath.substring(appRootStr.length(), targertAbsolutePath.length()).replace(".class", "").replace("/", ".");

        // 4
        Class<?> testClass;
        Object testClassInstance;
        try {
          testClass = Class.forName(targetClassName);
          testClassInstance = testClass.newInstance();
        } catch (Exception e) {
          throw new RuntimeException(e);
        }

     // *5
        for( Method method : testClass.getMethods() ) {

          TestAnno testAnnotation = method.getAnnotation(TestAnno.class);
          if ( testAnnotation == null ) continue;

          try {
            if ( testAnnotation.testFlg() )
              method.invoke(testClassInstance);
          } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
          }

        }


      });


      System.out.println("Test End");
    }



  }

}

*1 Dabei wird hier das Paket zum Laufwerkstest angegeben. Dieses Mal wird die Java-Datei unter dem Paketnamen [Test] als Ziel ausgewählt. → testRoot

*2 Verwenden Sie die Walk-Funktion, um die Java-Datei unter testRoot zu extrahieren Führen Sie eine Verzeichnisüberquerung durch. Wenn es sich um eine normale Datei handelt (dh wenn es sich um eine Klassendatei handelt), filtern Sie sie, um sie zu verarbeiten Nur Klassendateien unterliegen der Stream-Verarbeitung

*3 Hier wird die zu extrahierende Klassendatei als Zeichenfolge einschließlich des Paketnamens erfasst.

*4 Lassen Sie die Klasse als Reflexion testen Holen Sie sich eine Instanz

*5 Extrahieren Sie das Methodenobjekt aus dem erfassten Klassenobjekt und Diejenigen mit testAnnotation und testFlg von true aufrufen.

Mit dieser Prozedur konnte ich die Methoden mit @testAnnotation extrahieren.

Implementierung einer vom Test gestarteten Methode

Hier definieren wir eine Klasse mit einer Methode, die tatsächlich als Test gestartet wird.

package test;

import anno.TestAnno;

public class Test {

  @TestAnno(testFlg=true)
  public void testMethod() {


    String className = this.getClass().getName();
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
    System.out.println("invoked " + className + ":" + methodName);

  }

  @TestAnno(testFlg=false)
  public void testMethod2() {


    String className = this.getClass().getName();
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
    System.out.println("invoked " + className + ":" + methodName);

  }

  @TestAnno(testFlg=true)
  public void testMethod3() {


    String className = this.getClass().getName();
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
    System.out.println("invoked " + className + ":" + methodName);

  }

}

Nehmen Sie Einstellungen wie @TestAnno (testFlg = true) und vor Wenn Sie überprüfen, ob testFlg nur für Methoden eingeladen wird, die wahr sind Es hat gut funktioniert.

Das ist alles, Ich verstehe die Einstellungen und Inhalte des Kontextklassenladers nicht Ich werde es in meiner Freizeit noch einmal überprüfen.

Der schwierige Teil bei der Implementierung dieser Zeit bestand darin, den Paketnamen zu erhalten. Es besteht möglicherweise keine große Nachfrage nach einer solchen Implementierung, da nicht viele Websites referenziert werden konnten.

Dieses Mal dachte ich über den Implementierungsinhalt der Punkte nach, die ich über die Bewegung von Junit wunderte. Für Klassen und Methoden, die durch Festlegen von Anmerkungen aufgerufen werden Ich frage mich, ob eine ähnliche Implementierung vorgenommen wurde.

Zum Beispiel die automatische Verkabelung des Federgerüsts und das Scannen von Komponenten. Ich denke, es ist die gleiche Art zu denken.

Wenn ich eine Chance habe, würde ich gerne mehr über Reflexion erfahren.

Bei dieser Implementierung geht es um die Bewegung von Klassenlader und Reflexion Mir wurde klar, dass ich überhaupt nicht verstand Wenn ich einen Artikel über Java schreibe, werde ich die Details dazu untersuchen.

Viele der oben genannten Codes wurden ausgeschnitten. Bei Interesse wenden Sie sich bitte an Github. https://github.com/ktkt11122334/qiita/tree/master/test

Recommended Posts

JUnit Teststart versuchen Sie etwas
Machen Sie einen Unit-Test mit Junit.
[Java] JUnit4-Testfallbeispiel
Testen Sie die Web-API mit junit
Testen Sie private Methoden in JUnit
Testen Sie private Methoden in JUnit
[JUnit] Testen Sie die ausgelöste Ausnahme
Prüfung
Prüfung
Prüfung
Prüfung
junit
JUnit-Testbericht in Maven ausgeben
[Java] Testen Sie private Methoden mit JUnit
Testen Sie den Spring Framework Controller mit Junit
Reihenfolge der Vor- und Nachbearbeitung des JUnit-Unit-Tests
So filtern Sie den JUnit-Test in Gradle
Steuern Sie die Testreihenfolge in Junit4 mit einem Aufzählungstyp
So testen Sie den privaten Bereich mit JUnit
Der JUnit 5-Gradle-Test führt zu einem Fehler mit der Lombok-Annotation
Einführung eines automatisierten Java-Tests mit JUnit 5 + Gradle