获取@Category 在 JUnit 的一组测试中出现的次数的计数

我已经使用 Java、Selenium、Junit、Maven 开发了一整套自动化测试。


对于每个测试,他们有一个或多个 @Category 注释,描述每个测试涵盖的软件区域。例如:


@Test

@Category({com.example.core.categories.Priority1.class,

           com.example.core.categories.Export.class,

           com.example.core.categories.MemberData.class})



@Test

@Category({com.example.core.categories.Priority1.class,

           com.example.core.categories.Import.class,

           com.example.core.categories.MemberData.class})



@Test

@Ignore

@Category({com.example.core.categories.Priority2.class,

           com.example.core.categories.Import.class,

           com.example.core.categories.MemberData.class})

我想要做的是找到一种方法来计算包含任何给定类别的测试数量。所有可能的类别都是文件//com/example/core/categories夹中的文件名作为源列表。


我已经尝试构建一个 shell 脚本来进行字数统计,这似乎工作正常,但我认为会有更多“内置”的东西来处理 @Category。


我最大的问题是,即使我得到了正确的计数,一个或多个测试很可能被标记为 @Ignore,这应该会使测试 @Category 无效,但没有大量使用标志并逐行读取每个文件为了它抛出正确的计数。


有没有一种很好的方法来逐项列出@Ignore 中的@Category?


示例输出


| Category                                     | Count |

|----------------------------------------------|------:|

| com.example.core.categories.Export.class     | 1     |

| com.example.core.categories.Import.class     | 1     |

| com.example.core.categories.MemberData.class | 2     |

| com.example.core.categories.Priority1.class  | 2     |

| com.example.core.categories.Priority2.class  | 0     |

| com.example.core.categories.Priority3.class  | 0     |


慕容3067478
浏览 121回答 2
2回答

陪伴而非守候

动态“按类别测试”计算机(推荐方法)我尝试了一种在抽象层中使用计数器执行此操作的方法,但很痛苦,必须在每个测试方法的开头添加源代码。最后,这是我为满足您的需求而编写的源代码;它很重(反射......),但它对现有源代码的干扰较小,并且完全满足您的需求。首先,您必须创建一个Testsuite(包含各种其他套件,或直接包含您想要的所有测试类),以确保最后您想要统计数据的所有测试都已加载。在这个套件中,你必须实现一个“最终钩子” @AfterClass,当整个测试套件完全由JUnit管理时,它将被调用一次。这是我为您编写的测试套件实现:package misc.category;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import java.util.Vector;import java.util.concurrent.atomic.AtomicInteger;import org.junit.AfterClass;import org.junit.runner.RunWith;import org.junit.runners.Suite;@RunWith(Suite.class)@Suite.SuiteClasses({ UnitTestWithCategory.class })public class TestSuiteCountComputer {&nbsp; &nbsp; public static final String MAIN_TEST_PACKAGES = "misc.category";&nbsp; &nbsp; private static final Class<?>[] getClasses(final ClassLoader classLoader)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {&nbsp; &nbsp; &nbsp; &nbsp; Class<?> CL_class = classLoader.getClass();&nbsp; &nbsp; &nbsp; &nbsp; while (CL_class != java.lang.ClassLoader.class) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CL_class = CL_class.getSuperclass();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; java.lang.reflect.Field ClassLoader_classes_field = CL_class.getDeclaredField("classes");&nbsp; &nbsp; &nbsp; &nbsp; ClassLoader_classes_field.setAccessible(true);&nbsp; &nbsp; &nbsp; &nbsp; Vector<?> classVector = (Vector<?>) ClassLoader_classes_field.get(classLoader);&nbsp; &nbsp; &nbsp; &nbsp; Class<?>[] classes = new Class[classVector.size()]; // Creates an array to avoid concurrent modification&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // exception.&nbsp; &nbsp; &nbsp; &nbsp; return classVector.toArray(classes);&nbsp; &nbsp; }&nbsp; &nbsp; // Registers the information.&nbsp; &nbsp; private static final void registerTest(Map<String, AtomicInteger> testByCategoryMap, String category) {&nbsp; &nbsp; &nbsp; &nbsp; AtomicInteger count;&nbsp; &nbsp; &nbsp; &nbsp; if (testByCategoryMap.containsKey(category)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = testByCategoryMap.get(category);&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = new AtomicInteger(0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testByCategoryMap.put(category, count);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; count.incrementAndGet();&nbsp; &nbsp; }&nbsp; &nbsp; @AfterClass&nbsp; &nbsp; public static void tearDownAfterClass() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; Map<String, AtomicInteger> testByCategoryMap = new HashMap<>();&nbsp; &nbsp; &nbsp; &nbsp; ClassLoader classLoader = Thread.currentThread().getContextClassLoader();&nbsp; &nbsp; &nbsp; &nbsp; while (classLoader != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Class<?> classToCheck : getClasses(classLoader)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String packageName = classToCheck.getPackage() != null ? classToCheck.getPackage().getName() : "";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!packageName.startsWith(MAIN_TEST_PACKAGES))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // For each methods of the class.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Method method : classToCheck.getDeclaredMethods()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Class<?>[] categoryClassToRegister = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean ignored = false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Annotation annotation : method.getAnnotations()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (annotation instanceof org.junit.experimental.categories.Category) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categoryClassToRegister = ((org.junit.experimental.categories.Category) annotation).value();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (annotation instanceof org.junit.Ignore) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ignored = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Ignore this annotation.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (ignored) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If you want to compute count of ignored test.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; registerTest(testByCategoryMap, "(Ignored Tests)");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (categoryClassToRegister != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Class<?> categoryClass : categoryClassToRegister) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; registerTest(testByCategoryMap, categoryClass.getCanonicalName());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classLoader = classLoader.getParent();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("\nFinal Statistics:");&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Count of Tests\t\tCategory");&nbsp; &nbsp; &nbsp; &nbsp; for (Entry<String, AtomicInteger> info : testByCategoryMap.entrySet()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("\t" + info.getValue() + "\t\t" + info.getKey());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}你可以根据自己的需要,特别是我一开始创建的常量,来过滤包来考虑。那么你就没有比你已经做的更多的事情了。例如,这是我的小测试类:package misc.category;import org.junit.Test;import org.junit.experimental.categories.Category;public class UnitTestWithCategory {&nbsp; &nbsp; @Category({CategoryA.class, CategoryB.class})&nbsp; &nbsp; @Test&nbsp; &nbsp; public final void Test() {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("In Test 1");&nbsp; &nbsp; }&nbsp; &nbsp; @Category(CategoryA.class)&nbsp; &nbsp; @Test&nbsp; &nbsp; public final void Test2() {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("In Test 2");&nbsp; &nbsp; }}在这种情况下,输出是:In Test 1In Test 2Final Statistics:Count of Tests&nbsp; &nbsp; &nbsp; Category&nbsp; &nbsp; 1&nbsp; &nbsp; &nbsp; &nbsp;misc.category.CategoryB&nbsp; &nbsp; 2&nbsp; &nbsp; &nbsp; &nbsp;misc.category.CategoryA并使用包含@Ignore注释的测试用例:package misc.category;import org.junit.Ignore;import org.junit.Test;import org.junit.experimental.categories.Category;public class UnitTestWithCategory {&nbsp; &nbsp; @Category({CategoryA.class, CategoryB.class})&nbsp; &nbsp; @Test&nbsp; &nbsp; public final void Test() {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("In Test 1");&nbsp; &nbsp; }&nbsp; &nbsp; @Category(CategoryA.class)&nbsp; &nbsp; @Test&nbsp; &nbsp; public final void Test2() {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("In Test 2");&nbsp; &nbsp; }&nbsp; &nbsp; @Category(CategoryA.class)&nbsp; &nbsp; @Ignore&nbsp; &nbsp; @Test&nbsp; &nbsp; public final void Test3() {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("In Test 3");&nbsp; &nbsp; }&nbsp; &nbsp;}你得到输出:In Test 1In Test 2Final Statistics:Count of Tests&nbsp; &nbsp; &nbsp; Category&nbsp; &nbsp; 1&nbsp; &nbsp; &nbsp; &nbsp;(Ignored Tests)&nbsp; &nbsp; 1&nbsp; &nbsp; &nbsp; &nbsp;misc.category.CategoryB&nbsp; &nbsp; 2&nbsp; &nbsp; &nbsp; &nbsp;misc.category.CategoryA如果需要,您可以轻松删除“(Ignored Tests)”注册,当然还可以根据需要调整输出。这个最终版本的好处是,它将处理真正加载/执行的测试类,因此您将获得已执行内容的真实统计数据,而不是像您目前获得的静态统计数据.静态“按类别测试”计算机如果您想像您问的那样对现有源代码无所事事,这是一种静态执行按类别计算的测试的方法。这是StaticTestWithCategoryCounter我为你写的:import java.io.File;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.Vector;import java.util.concurrent.atomic.AtomicInteger;public class StaticTestWithCategoryCounter {&nbsp; &nbsp; public static final String ROOT_DIR_TO_SCAN = "bin";&nbsp; &nbsp; public static final String MAIN_TEST_PACKAGES = "misc.category";&nbsp; &nbsp; private static final Class<?>[] getClasses(final ClassLoader classLoader)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {&nbsp; &nbsp; &nbsp; &nbsp; Class<?> CL_class = classLoader.getClass();&nbsp; &nbsp; &nbsp; &nbsp; while (CL_class != java.lang.ClassLoader.class) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CL_class = CL_class.getSuperclass();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; java.lang.reflect.Field ClassLoader_classes_field = CL_class.getDeclaredField("classes");&nbsp; &nbsp; &nbsp; &nbsp; ClassLoader_classes_field.setAccessible(true);&nbsp; &nbsp; &nbsp; &nbsp; Vector<?> classVector = (Vector<?>) ClassLoader_classes_field.get(classLoader);&nbsp; &nbsp; &nbsp; &nbsp; Class<?>[] classes = new Class[classVector.size()]; // Creates an array to avoid concurrent modification&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // exception.&nbsp; &nbsp; &nbsp; &nbsp; return classVector.toArray(classes);&nbsp; &nbsp; }&nbsp; &nbsp; // Registers the information.&nbsp; &nbsp; private static final void registerTest(Map<String, AtomicInteger> testByCategoryMap, String category) {&nbsp; &nbsp; &nbsp; &nbsp; AtomicInteger count;&nbsp; &nbsp; &nbsp; &nbsp; if (testByCategoryMap.containsKey(category)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = testByCategoryMap.get(category);&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = new AtomicInteger(0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testByCategoryMap.put(category, count);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; count.incrementAndGet();&nbsp; &nbsp; }&nbsp; &nbsp; public static void computeCategoryCounters() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; Map<String, AtomicInteger> testByCategoryMap = new HashMap<>();&nbsp; &nbsp; &nbsp; &nbsp; ClassLoader classLoader = Thread.currentThread().getContextClassLoader();&nbsp; &nbsp; &nbsp; &nbsp; while (classLoader != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Class<?> classToCheck : getClasses(classLoader)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String packageName = classToCheck.getPackage() != null ? classToCheck.getPackage().getName() : "";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!packageName.startsWith(MAIN_TEST_PACKAGES))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // For each methods of the class.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Method method : classToCheck.getDeclaredMethods()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Class<?>[] categoryClassToRegister = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean ignored = false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Annotation annotation : method.getAnnotations()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (annotation instanceof org.junit.experimental.categories.Category) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categoryClassToRegister = ((org.junit.experimental.categories.Category) annotation).value();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (annotation instanceof org.junit.Ignore) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ignored = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Ignore this annotation.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (ignored) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If you want to compute count of ignored test.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; registerTest(testByCategoryMap, "(Ignored Tests)");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (categoryClassToRegister != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Class<?> categoryClass : categoryClassToRegister) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; registerTest(testByCategoryMap, categoryClass.getCanonicalName());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classLoader = classLoader.getParent();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("\nFinal Statistics:");&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Count of Tests\t\tCategory");&nbsp; &nbsp; &nbsp; &nbsp; for (Entry<String, AtomicInteger> info : testByCategoryMap.entrySet()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("\t" + info.getValue() + "\t\t" + info.getKey());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public static List<String> listNameOfAvailableClasses(String rootDirectory, File directory, String packageName) throws ClassNotFoundException {&nbsp; &nbsp; &nbsp; &nbsp; List<String> classeNameList = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; if (!directory.exists()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return classeNameList;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; File[] files = directory.listFiles();&nbsp; &nbsp; &nbsp; &nbsp; for (File file : files) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (file.isDirectory()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (file.getName().contains("."))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classeNameList.addAll(listNameOfAvailableClasses(rootDirectory, file, packageName));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (file.getName().endsWith(".class")) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String qualifiedName = file.getPath().substring(rootDirectory.length() + 1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; qualifiedName = qualifiedName.substring(0, qualifiedName.length() - 6).replaceAll(File.separator, ".");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (packageName ==null || qualifiedName.startsWith(packageName))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classeNameList.add(qualifiedName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return classeNameList;&nbsp; &nbsp; }&nbsp; &nbsp; public static List<Class<?>> loadAllAvailableClasses(String rootDirectory, String packageName) throws ClassNotFoundException {&nbsp; &nbsp; &nbsp; &nbsp; List<String> classeNameList = listNameOfAvailableClasses(rootDirectory, new File(rootDirectory), packageName);&nbsp; &nbsp; &nbsp; &nbsp; List<Class<?>> classes = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; for (final String className: classeNameList) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes.add(Class.forName(className));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return classes;&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadAllAvailableClasses(ROOT_DIR_TO_SCAN, MAIN_TEST_PACKAGES);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; computeCategoryCounters();&nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}您只需要在开始时调整两个常量即可指定:(字节码)类在哪里您对哪个主包感兴趣(您能否将其设置null为考虑 100% 可用包)这个新版本的想法:列出与您的 2 个常量匹配的所有类文件加载所有对应的类使用未修改的动态版本源代码(现在类已加载)如果您需要更多信息,请告诉我。

慕码人2483693

使用番石榴,ClassPath您可以执行以下操作:首先加载类别:private static List<Class<?>> getCategories(ClassPath classPath) {&nbsp; return classPath.getAllClasses()&nbsp; &nbsp; &nbsp; .stream()&nbsp; &nbsp; &nbsp; .filter(classInfo -> classInfo.getPackageName().startsWith(CATEGORIES_PACKAGE))&nbsp; &nbsp; &nbsp; .map(ClassPath.ClassInfo::load)&nbsp; &nbsp; &nbsp; .collect(Collectors.toList());}然后计算频率。这个方法返回一个Mapfrom 类别Class<?>到它的频率:private static Map<Class<?>, Long> getCategoryFrequency(ClassPath classPath) {&nbsp; return classPath.getAllClasses()&nbsp; &nbsp; .stream()&nbsp; &nbsp; .filter(classInfo -> classInfo.getPackageName().startsWith(APPLICATION_PACKAGE))&nbsp; &nbsp; .map(ClassPath.ClassInfo::load)&nbsp; &nbsp; .map(Class::getMethods)&nbsp; &nbsp; .flatMap(Arrays::stream)&nbsp; &nbsp; .filter(method -> method.getAnnotation(Test.class) != null)// Only tests&nbsp; &nbsp; .filter(method -> method.getAnnotation(Ignore.class) == null) // Without @Ignore&nbsp; &nbsp; .map(method -> method.getAnnotation(Category.class))&nbsp; &nbsp; .filter(Objects::nonNull)&nbsp; &nbsp; .map(Category::value)&nbsp; &nbsp; .flatMap(Arrays::stream)&nbsp; &nbsp; .collect(groupingBy(Function.identity(), Collectors.counting()));}最后打印结果:System.out.println("Category | Frequency");for (Class<?> category : categories) {&nbsp; System.out.println(category.getSimpleName() + " | " + categoryFrequency.getOrDefault(category, 0L));}全班名单:public class CategoriesCounter {&nbsp; private static final String CATEGORIES_PACKAGE = "com.example.core.categories";&nbsp; private static final String APPLICATION_PACKAGE = "com.example.core";&nbsp; public static void main(String[] args) throws Throwable {&nbsp; &nbsp; ClassPath classPath = ClassPath.from(CategoriesCounter.class.getClassLoader());&nbsp; &nbsp; List<Class<?>> categories = getCategories(classPath);&nbsp; &nbsp; Map<Class<?>, Long> categoryFrequency = getCategoryFrequency(classPath);&nbsp; &nbsp; System.out.println("Category | Frequency");&nbsp; &nbsp; for (Class<?> category : categories) {&nbsp; &nbsp; &nbsp; System.out.println(category.getSimpleName() + " | " + categoryFrequency.getOrDefault(category, 0L));&nbsp; &nbsp; }&nbsp; }&nbsp; private static List<Class<?>> getCategories(ClassPath classPath) {&nbsp; &nbsp; return classPath.getAllClasses()&nbsp; &nbsp; &nbsp; &nbsp; .stream()&nbsp; &nbsp; &nbsp; &nbsp; .filter(classInfo -> classInfo.getPackageName().startsWith(CATEGORIES_PACKAGE))&nbsp; &nbsp; &nbsp; &nbsp; .map(ClassPath.ClassInfo::load)&nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.toList());&nbsp; }&nbsp; private static Map<Class<?>, Long> getCategoryFrequency(ClassPath classPath) {&nbsp; &nbsp; return classPath.getAllClasses()&nbsp; &nbsp; &nbsp; &nbsp; .stream()&nbsp; &nbsp; &nbsp; &nbsp; .filter(classInfo -> classInfo.getPackageName().startsWith(APPLICATION_PACKAGE))&nbsp; &nbsp; &nbsp; &nbsp; .map(ClassPath.ClassInfo::load)&nbsp; &nbsp; &nbsp; &nbsp; .map(Class::getMethods)&nbsp; &nbsp; &nbsp; &nbsp; .flatMap(Arrays::stream)&nbsp; &nbsp; &nbsp; &nbsp; .filter(method -> method.getAnnotation(Test.class) != null)// Only tests&nbsp; &nbsp; &nbsp; &nbsp; .filter(method -> method.getAnnotation(Ignore.class) == null) // Without @Ignore&nbsp; &nbsp; &nbsp; &nbsp; .map(method -> method.getAnnotation(Category.class))&nbsp; &nbsp; &nbsp; &nbsp; .filter(Objects::nonNull)&nbsp; &nbsp; &nbsp; &nbsp; .map(Category::value)&nbsp; &nbsp; &nbsp; &nbsp; .flatMap(Arrays::stream)&nbsp; &nbsp; &nbsp; &nbsp; .collect(groupingBy(Function.identity(), Collectors.counting()));&nbsp; }}在类路径上使用这个测试类:public class Test1 {&nbsp; @FastTest&nbsp; @Category(value = FastTest.class)&nbsp; @Test&nbsp; public void a() {&nbsp; }&nbsp; @FastTest&nbsp; @Category(value = FastTest.class)&nbsp; @Test&nbsp; public void d() {&nbsp; }&nbsp; @Category(value = SlowTest.class)&nbsp; @Test&nbsp; public void b() {&nbsp; }&nbsp; @Category(value = SlowTest.class)&nbsp; @Test&nbsp; @Ignore&nbsp; public void c() {&nbsp; }}该CategoriesCounter收益率:Category | FrequencySlowTest | 1FastTest | 2
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java