Java 确定哪些测试用例涵盖了一种方法

Java 确定哪些测试用例涵盖了一种方法,java,jakarta-ee,selenium,junit,code-coverage,Java,Jakarta Ee,Selenium,Junit,Code Coverage,我正在从事的当前项目要求我编写一个工具,在web应用程序上运行功能测试,并输出方法覆盖率数据,记录哪个测试用例遍历哪个方法 详细信息: 被测试的web应用程序将是在servlet容器(例如Tomcat)中运行的JavaEE应用程序。功能测试将使用JUnit以Selenium编写。一些方法将被注释,以便在部署到测试环境之前对其进行检测。执行Selenium测试后,将记录带注释方法的执行情况 问题:该项目的最大障碍是找到一种方法将测试用例的执行与方法的遍历联系起来,特别是测试和应用程序在不同的JVM

我正在从事的当前项目要求我编写一个工具,在web应用程序上运行功能测试,并输出方法覆盖率数据,记录哪个测试用例遍历哪个方法

详细信息: 被测试的web应用程序将是在servlet容器(例如Tomcat)中运行的JavaEE应用程序。功能测试将使用JUnit以Selenium编写。一些方法将被注释,以便在部署到测试环境之前对其进行检测。执行Selenium测试后,将记录带注释方法的执行情况

问题:该项目的最大障碍是找到一种方法将测试用例的执行与方法的遍历联系起来,特别是测试和应用程序在不同的JVM上运行,并且无法将测试用例的名称传递给应用程序,并且无法使用线程信息将测试与代码执行联系起来

建议的解决方案:我的解决方案将包括使用执行时间:我扩展JUnit框架以记录执行测试用例的时间,并对应用程序进行指令化,以节省遍历方法的时间。我尝试使用相关性将测试用例与方法覆盖率联系起来

预期问题:此解决方案假定测试用例按顺序执行,并且测试用例在下一个测试用例开始之前结束。这个假设对JUnit合理吗

问题:简单地说,我能听听您对建议的解决方案的意见吗,也许还有关于如何改进并使其在大多数Java EE应用程序上更健壮、更实用的建议?或者导致已经实施的解决方案

多谢各位


编辑:要添加更多需求,该工具应该能够在任何Java EE应用程序上工作,并且需要在应用程序中进行最少的配置或更改。虽然我知道这不是一个现实的需求,但该工具至少不需要对应用程序本身进行任何巨大的修改,比如添加类或代码行。

您是否看过现有的覆盖工具(Cobertura、Clover、Emma等)。我不确定其中一个是否能够将覆盖率数据链接到测试用例,但至少使用开源的Cobertura,您可能能够执行以下操作:

  • 用cobertura为班级制作乐器
  • 部署插入指令的web应用程序
  • 启动测试套件
    • 每次测试后,调用web应用程序上的URL,将覆盖率数据保存到以刚刚运行的测试命名的文件中,并重置覆盖率数据
  • 测试套件完成后,为每个保存的文件生成一个cobertura报告。每个报告都将告诉测试运行了哪些代码

如果您需要合并报告,我想使用cobertura API从保存的文件集生成它应该不会太难。

您看过现有的覆盖工具(cobertura、Clover、Emma等)吗。我不确定其中一个是否能够将覆盖率数据链接到测试用例,但至少使用开源的Cobertura,您可能能够执行以下操作:

  • 用cobertura为班级制作乐器
  • 部署插入指令的web应用程序
  • 启动测试套件
    • 每次测试后,调用web应用程序上的URL,将覆盖率数据保存到以刚刚运行的测试命名的文件中,并重置覆盖率数据
  • 测试套件完成后,为每个保存的文件生成一个cobertura报告。每个报告都将告诉测试运行了哪些代码

如果您需要一个合并的报告,我想使用cobertura API从保存的文件集生成它应该不会太难。

您提出的解决方案似乎是合理的,除了建议的解决方案按时间关联测试和请求之外。我以前试过做这类事情,而且效果很好。大多数时候。除非您非常仔细地编写JUnit代码,否则您将遇到很多问题,因为两台机器之间的时间差异,或者如果您只有一台机器,那么只需将一个时间与另一个时间进行匹配

更好的解决方案是实现一个,您可以将其插入Web应用程序的server.xml的生命周期中。Valves的优点是您可以在server.xml中定义它们,因此您根本不需要接触webapp

您将需要实现invoke()。最好的出发点可能是。这是AccessLogValve中的实现:

/**
 * Log a message summarizing the specified request and response, according
 * to the format specified by the <code>pattern</code> property.
 *
 * @param request Request being processed
 * @param response Response being processed
 *
 * @exception IOException if an input/output error has occurred
 * @exception ServletException if a servlet error has occurred
 */
public void invoke(Request request, Response response) throws IOException,
        ServletException {

    if (started && getEnabled()) {                
        // Pass this request on to the next valve in our pipeline
        long t1 = System.currentTimeMillis();

        getNext().invoke(request, response);

        long t2 = System.currentTimeMillis();
        long time = t2 - t1;

        if (logElements == null || condition != null
                && null != request.getRequest().getAttribute(condition)) {
            return;
        }

        Date date = getDate();
        StringBuffer result = new StringBuffer(128);

        for (int i = 0; i < logElements.length; i++) {
            logElements[i].addElement(result, date, request, response, time);
        }

        log(result.toString());
    } else
        getNext().invoke(request, response);       
}
所有这些只是记录您访问过它的事实

你需要安装一个新的阀门。对于您的请求,您传递一个唯一的id作为URL的参数,该参数用于标识您正在运行的测试。在调用()之前和之后,您的阀门将完成所有繁重的提升。如果需要,可以删除getNext().invoke()的唯一参数

为了测量覆盖率,您可以使用JB Nizet建议的覆盖率工具,该工具基于您传递的唯一id

那么,从junit开始,如果您最初的调用是

@Test void testSomething() {
    selenium.open("http://localhost/foo.jsp?bar=14");
}
您可以将其更改为:

@Test void testSomething() {
    selenium.open("http://localhost/foo.jsp?bar=14&testId=testSomething");
}

然后,您将在阀中选择参数testId。

您提出的解决方案似乎是合理的,除了通过计时将测试和请求关联起来的建议解决方案。我以前试过做这类事情,而且效果很好。大多数时候。除非您非常仔细地编写JUnit代码,否则您将遇到很多问题,因为两台机器之间的时间差异,或者如果您只有一台机器,那么只需将一个时间与另一个时间进行匹配

更好的解决方案是实现一个,您可以将其插入Web应用程序的server.xml的生命周期中。Valves的优点是您可以在server.xml中定义它们,因此您根本不需要接触webapp