2017-09-22 1 views
1

J'ajoute des tests dans Bazel, mais je ne veux pas écrire une règle de test pour chaque fichier de test. Cependant, chaque règle de test nécessite un test_class - la classe de test en cours d'exécution, il n'y a donc pas de moyen facile d'exécuter tous les tests avec une seule règle java_test. Y at-il un travail autour de là où je n'aurais pas besoin de spécifier un test_class et juste exécuter tous les tests à la fois?Comment exécuter tous les tests dans Bazel à partir d'une seule règle java_test()?

Répondre

2

Vous pouvez écrire une classe de suites de tests JUnit, qui exécutera vos autres tests. Par exemple, si vous avez des classes de test Test1.java et Test2.java, vous pouvez faire quelque chose comme ceci:

AllTests.java

import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
import org.junit.runners.Suite.SuiteClasses; 

@RunWith(Suite.class) 
@SuiteClasses({ 
    Test1.class, 
    Test2.class 
}) 
public class AllTests {} 

BUILD

java_test(
    name = "AllTests", 
    test_class = "AllTests", 
    srcs = [ 
     "AllTests.java", 
     "Test1.java", 
     "Test2.java", 
    ], 
) 

EDIT en réponse au commentaire :

Si vous ne souhaitez pas spécifier les noms de classe de test dans votre suite de tests, vous pouvez faire quelque chose via la réflexion. L'exemple suivant suppose que tous vos tests sont dans le paquet « com.foo » et que tous les tests sont SRCs de la règle java_test:

package com.foo; 

import java.io.File; 
import java.io.IOException; 
import java.net.URLClassLoader; 
import java.util.Enumeration; 
import java.util.Set; 
import java.util.TreeSet; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipFile; 
import junit.framework.JUnit4TestAdapter; 
import junit.framework.TestSuite; 
import org.junit.runner.RunWith; 

@RunWith(org.junit.runners.AllTests.class) 
public class AllTests { 
    public static TestSuite suite() throws IOException { 
    TestSuite suite = new TestSuite(); 
    URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); 
    // The first entry on the classpath contains the srcs from java_test 
    findClassesInJar(new File(classLoader.getURLs()[0].getPath())) 
     .stream() 
     .map(c -> { 
      try { 
      return Class.forName(c); 
      } catch (ClassNotFoundException e) { 
      throw new RuntimeException(e); 
      } 
     }) 
     .filter(clazz -> !clazz.equals(AllTests.class)) 
     .map(JUnit4TestAdapter::new) 
     .forEach(suite::addTest); 
    return suite; 
    } 

    private static Set<String> findClassesInJar(File jarFile) { 
    Set<String> classNames = new TreeSet<>(); 
    try { 
     try (ZipFile zipFile = new ZipFile(jarFile)) { 
     Enumeration<? extends ZipEntry> entries = zipFile.entries(); 
     while (entries.hasMoreElements()) { 
      String entryName = entries.nextElement().getName(); 
      if (entryName.startsWith("com/foo") && entryName.endsWith(".class")) { 
      int classNameEnd = entryName.length() - ".class".length(); 
      classNames.add(entryName.substring(0, classNameEnd).replace('/', '.')); 
      } 
     } 
     } 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } 
    return classNames; 
    } 
} 
+0

Merci Adam, je l'ai fait essayé, et bien que cela fonctionne, j'étais en essayant d'éviter d'avoir des classes java supplémentaires et de résoudre cela uniquement avec Bazel. Je voulais aussi ne pas avoir à ajouter les classes de test individuellement. Fondamentalement, je veux que mes classes de test soient automatiquement récupérées sans que je doive les spécifier explicitement. Je devrais aller avec cette approche si je ne trouve rien de mieux. – Zeitgeist

+0

Vous pouvez faire en sorte que AllTests utilise la réflexion pour trouver vos tests. Je ne suis pas au courant de quoi que ce soit qui le fait par défaut, mais je vais éditer ma réponse avec un exemple possible – Adam

+0

Terminé en utilisant cette solution parce que ma propre solution ne générait pas de couverture fusionnée. – Zeitgeist

2

En Bazel, nous avons écrit un Junit personnalisé Suite qui trouve toutes les classes de Junit sur le chemin de classe dans ou sous le package de la classe annotée. Vous pouvez trouver le code here. C'est assez court et direct et vous pouvez le copier dans votre projet ou faire quelque chose de similaire.

Vous pouvez avoir vos règles comme ceci:

java_library(
    name = "tests", 
    test_only = 1, 
    srcs = glob(["*.java"] 
) 
java_test(
    name = "MyTests", 
    test_class = "MyTests", 
    runtime_deps = ":tests" 
) 

et le fichier MyTests.java devrait ressembler à ceci:

import package.ClasspathSuite; 

import org.junit.runner.RunWith; 

@RunWith(ClasspathSuite.class) 
public class MyTests { } 
+0

Merci Irina, c'est en fait ce que je cherchais, sauf qu'au cours du week-end, je suis venu avec une solution même shorted pour moi-même. Faites-moi savoir s'il y a des préoccupations concernant la solution que j'ai acceptée. Cela fonctionne bien pour moi, mais je suis nouveau à bazel, et peut-être négligé quelque chose ... – Zeitgeist

1

Voici une solution qui ne nécessite pas l'utilisation Suite. Gardez à l'esprit, il va générer des rapports de couverture fichiers .dat individuellement pour chaque classe.

macro .bzl pour gérer tous les tests:

def run_tests(name, srcs, package, deps): 
    for src in srcs: 
    src_name = src[:-5] 
    native.java_test(name=src_name, test_class=package + "." + src_name, srcs=srcs, deps=deps, size="small") 

Calling cette macro de l'emplacement des fichiers de test:

run_tests(
    name = "test", 
    srcs = glob(["*Test.java"]), 
    package = "pkg", 
    deps = [ 
     ":src_lib", 
    ] 
)