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

计算@Category在JUnit的一组测试中出现的次数,第1张

计算@Category在JUnit的一组测试中出现的次数 动态“按类别测试”计算机

(推荐方法)

我尝试了一种使用抽象层中的计数器执行此 *** 作的方法,但是这很痛苦,必须在每个Test方法的开头添加源代码

最后,这是我为满足您的需求而编写的源代码。它很繁重(反射…),但是它对现有源代码的干扰较小,可以完全满足您的需求。

首先,您必须创建一个

Testsuite
(包含其他各种套件,或者直接包含您想要的所有Test类),以确保最后已经加载了您想要统计的所有Test。

在此套件中,您必须实现一个“最终挂钩”

@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 {    public static final String MAIN_TEST_PACKAGES = "misc.category";    private static final Class<?>[] getClasses(final ClassLoader classLoader) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {        Class<?> CL_class = classLoader.getClass();        while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass();        }        java.lang.reflect.Field ClassLoader_classes_field = CL_class.getDeclaredField("classes");        ClassLoader_classes_field.setAccessible(true);        Vector<?> classVector = (Vector<?>) ClassLoader_classes_field.get(classLoader);        Class<?>[] classes = new Class[classVector.size()]; // Creates an array to avoid concurrent modification     // exception.        return classVector.toArray(classes);    }    // Registers the information.    private static final void registerTest(Map<String, AtomicInteger> testByCategoryMap, String category) {        AtomicInteger count;        if (testByCategoryMap.containsKey(category)) { count = testByCategoryMap.get(category);        } else { count = new AtomicInteger(0); testByCategoryMap.put(category, count);        }        count.incrementAndGet();    }    @AfterClass    public static void tearDownAfterClass() throws Exception {        Map<String, AtomicInteger> testByCategoryMap = new HashMap<>();        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();        while (classLoader != null) { for (Class<?> classToCheck : getClasses(classLoader)) {     String packageName = classToCheck.getPackage() != null ? classToCheck.getPackage().getName() : "";     if (!packageName.startsWith(MAIN_TEST_PACKAGES))         continue;     // For each methods of the class.     for (Method method : classToCheck.getDeclaredMethods()) {         Class<?>[] categoryClassToRegister = null;         boolean ignored = false;         for (Annotation annotation : method.getAnnotations()) {  if (annotation instanceof org.junit.experimental.categories.Category) {      categoryClassToRegister = ((org.junit.experimental.categories.Category) annotation).value();  } else if (annotation instanceof org.junit.Ignore) {      ignored = true;  } else {      // Ignore this annotation.      continue;  }         }         if (ignored) {  // If you want to compute count of ignored test.  registerTest(testByCategoryMap, "(Ignored Tests)");         } else if (categoryClassToRegister != null) {  for (Class<?> categoryClass : categoryClassToRegister) {      registerTest(testByCategoryMap, categoryClass.getCanonicalName());  }         }     } } classLoader = classLoader.getParent();        }        System.out.println("nFinal Statistics:");        System.out.println("Count of TeststtCategory");        for (Entry<String, AtomicInteger> info : testByCategoryMap.entrySet()) { System.out.println("t" + info.getValue() + "tt" + info.getKey());        }    }}

您可以适应您的需求,尤其是我在开始时创建的常数,以对软件包进行考虑。

这样一来,您只需要完成已有的工作即可。

例如,这是我很小的测试类:

package misc.category;import org.junit.Test;import org.junit.experimental.categories.Category;public class UnitTestWithCategory {    @Category({CategoryA.class, CategoryB.class})    @Test    public final void Test() {        System.out.println("In Test 1");    }    @Category(CategoryA.class)    @Test    public final void Test2() {        System.out.println("In Test 2");    }}

在这种情况下,输出为:

In Test 1In Test 2Final Statistics:Count of Tests      Category    1       misc.category.CategoryB    2       misc.category.CategoryA

并带有包含

@Ignore
注释的测试用例:

package misc.category;import org.junit.Ignore;import org.junit.Test;import org.junit.experimental.categories.Category;public class UnitTestWithCategory {    @Category({CategoryA.class, CategoryB.class})    @Test    public final void Test() {        System.out.println("In Test 1");    }    @Category(CategoryA.class)    @Test    public final void Test2() {        System.out.println("In Test 2");    }    @Category(CategoryA.class)    @Ignore    @Test    public final void Test3() {        System.out.println("In Test 3");    }   }

您将获得输出:

In Test 1In Test 2Final Statistics:Count of Tests      Category    1       (Ignored Tests)    1       misc.category.CategoryB    2       misc.category.CategoryA

您可以根据需要轻松删除“(已忽略的测试)”注册,并且当然可以根据需要调整输出。

最终版本的好处是它将处理已经真正加载/执行的测试类,因此您将获得有关已执行内容的真实统计信息,而不是到目前为止的静态统计信息。

静态“按类别测试”计算机

如果您希望像您所要求的那样与现有源代码无关,那么这是一种静态执行“ 按类别测试” 计算的方法。

这是

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 {    public static final String ROOT_DIR_TO_SCAN = "bin";    public static final String MAIN_TEST_PACKAGES = "misc.category";    private static final Class<?>[] getClasses(final ClassLoader classLoader) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {        Class<?> CL_class = classLoader.getClass();        while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass();        }        java.lang.reflect.Field ClassLoader_classes_field = CL_class.getDeclaredField("classes");        ClassLoader_classes_field.setAccessible(true);        Vector<?> classVector = (Vector<?>) ClassLoader_classes_field.get(classLoader);        Class<?>[] classes = new Class[classVector.size()]; // Creates an array to avoid concurrent modification     // exception.        return classVector.toArray(classes);    }    // Registers the information.    private static final void registerTest(Map<String, AtomicInteger> testByCategoryMap, String category) {        AtomicInteger count;        if (testByCategoryMap.containsKey(category)) { count = testByCategoryMap.get(category);        } else { count = new AtomicInteger(0); testByCategoryMap.put(category, count);        }        count.incrementAndGet();    }    public static void computeCategoryCounters() throws Exception {        Map<String, AtomicInteger> testByCategoryMap = new HashMap<>();        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();        while (classLoader != null) { for (Class<?> classToCheck : getClasses(classLoader)) {     String packageName = classToCheck.getPackage() != null ? classToCheck.getPackage().getName() : "";     if (!packageName.startsWith(MAIN_TEST_PACKAGES))         continue;     // For each methods of the class.     for (Method method : classToCheck.getDeclaredMethods()) {         Class<?>[] categoryClassToRegister = null;         boolean ignored = false;         for (Annotation annotation : method.getAnnotations()) {  if (annotation instanceof org.junit.experimental.categories.Category) {      categoryClassToRegister = ((org.junit.experimental.categories.Category) annotation).value();  } else if (annotation instanceof org.junit.Ignore) {      ignored = true;  } else {      // Ignore this annotation.      continue;  }         }         if (ignored) {  // If you want to compute count of ignored test.  registerTest(testByCategoryMap, "(Ignored Tests)");         } else if (categoryClassToRegister != null) {  for (Class<?> categoryClass : categoryClassToRegister) {      registerTest(testByCategoryMap, categoryClass.getCanonicalName());  }         }     } } classLoader = classLoader.getParent();        }        System.out.println("nFinal Statistics:");        System.out.println("Count of TeststtCategory");        for (Entry<String, AtomicInteger> info : testByCategoryMap.entrySet()) { System.out.println("t" + info.getValue() + "tt" + info.getKey());        }    }    public static List<String> listNameOfAvailableClasses(String rootDirectory, File directory, String packageName) throws ClassNotFoundException {        List<String> classeNameList = new ArrayList<>();        if (!directory.exists()) { return classeNameList;        }        File[] files = directory.listFiles();        for (File file : files) { if (file.isDirectory()) {     if (file.getName().contains("."))         continue;     classeNameList.addAll(listNameOfAvailableClasses(rootDirectory, file, packageName)); } else if (file.getName().endsWith(".class")) {     String qualifiedName = file.getPath().substring(rootDirectory.length() + 1);     qualifiedName = qualifiedName.substring(0, qualifiedName.length() - 6).replaceAll(File.separator, ".");     if (packageName ==null || qualifiedName.startsWith(packageName))         classeNameList.add(qualifiedName); }        }        return classeNameList;    }    public static List<Class<?>> loadAllAvailableClasses(String rootDirectory, String packageName) throws ClassNotFoundException {        List<String> classeNameList = listNameOfAvailableClasses(rootDirectory, new File(rootDirectory), packageName);        List<Class<?>> classes = new ArrayList<>();        for (final String className: classeNameList) { classes.add(Class.forName(className));        }        return classes;    }    public static void main(String[] args) {        try { loadAllAvailableClasses(ROOT_DIR_TO_SCAN, MAIN_TEST_PACKAGES); computeCategoryCounters();        } catch (Exception e) { e.printStackTrace();        }    }}

您只需要在开始指定两个常量时就对其进行调整即可:

  • (字节码)类在哪里
  • 哪个主程序包很有趣(您可以将其设置
    null
    为100%可用的程序包)

这个新版本的想法是:

  • 列出与您的2个常量匹配的所有类文件
  • 加载所有对应的类
  • 使用未经修改的动态版本源代码(现在已经加载了类)

让我知道您是否需要更多信息。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5478674.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-12
下一篇 2022-12-12

发表评论

登录后才能评论

评论列表(0条)

保存