简体   繁体   English

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

[英]Determining which test cases covered a method

The current project I'm working on requires me to write a tool which runs functional tests on a web application, and outputs method coverage data, recording which test case traversed which method. 我正在从事的当前项目要求我编写一个工具,该工具可以在Web应用程序上运行功能测试,并输出方法覆盖率数据,记录哪个测试用例遍历了哪个方法。

Details: The web application under test will be a Java EE application running in a servlet container (eg. Tomcat). 详细信息:被测试的Web应用程序将是在servlet容器(例如Tomcat)中运行的Java EE应用程序。 The functional tests will be written in Selenium using JUnit. 功能测试将使用JUnit用Selenium编写。 Some methods will be annotated so that they will be instrumented prior to deployement into the test enviornment. 一些方法将被注释,以便在部署到测试环境之前对其进行检测。 Once the Selenium tests are executed, the execution of annotated methods will be recorded. 执行Selenium测试后,将记录带注释的方法的执行。

Problem : The big obstacle of this project is finding a way to relate an execution of a test case with the traversal of a method, especially that the tests and the application run on different JVMs, and there's no way to transmit the name of the test case down the application, and no way in using thread information to relate test with code execution. 问题 :该项目的最大障碍是找到一种方法,将测试用例的执行与方法的遍历相关联,特别是测试和应用程序在不同的JVM上运行,并且无法传递测试的名称降低应用程序性能,并且无法使用线程信息将测试与代码执行相关联。

Proposed solution: My solution would consist of using the time of execution: I extend the JUnit framework to record the time the test case was executed, and I instrument the application so that it saves the time the method was traversed. 建议的解决方案:我的解决方案将包括执行时间:我扩展了JUnit框架以记录执行测试用例的时间,并且对应用程序进行检测,从而节省了遍历该方法的时间。 And I try to use correlation to link the test case with method coverage. 而且,我尝试使用相关性将测试案例与方法覆盖率关联起来。

Expected problems: This solution assumes that test cases are executed sequentially, and a test case ends befores the next one starts. 预期的问题:此解决方案假定测试用例是按顺序执行的,并且一个测试用例在下一个测试用例开始之前已结束。 Is this assumption reasonable with JUnit? 这个假设对JUnit合理吗?

Question: Simply, can I have your input on the proposed solution, and perhaps suggestions on how to improve and make it more robust and functional on most Java EE applications? 问:简单地说,我是否可以就建议的解决方案提供您的意见,或者就如何改进大多数Java EE应用程序使其更健壮和更有效地提出建议? Or leads to already implemented solutions? 还是导致已经实施的解决方案?

Thank you 谢谢

Edit : To add more requirements, the tool should be able to work on any Java EE application and require the least amount of configuration or change in the application. 编辑 :要添加更多要求,该工具应该能够在任何Java EE应用程序上运行,并且需要最少的配置或更改应用程序。 While I know it isn't a realistic requirement, the tool should at least not require any huge modification of the application itself, like adding classes or lines of code. 虽然我知道这不是一个现实的要求,但是该工具至少应该不需要对应用程序本身进行任何大的修改,例如添加类或代码行。

Have you looked at existing coverage tools (Cobertura, Clover, Emma, ...). 您是否看过现有的报道工具(Cobertura,Clover,Emma等)。 I'm not sure if one of them is able to link the coverage data to test cases, but at least with Cobertura, which is open-source, you might be able to do the following: 我不确定其中之一是否能够将coverage数据链接到测试用例,但是至少使用开源的Cobertura,您也许可以执行以下操作:

  • instrument the classes with cobertura 与cobertura一起上课
  • deploy the instrumented web app 部署检测的Web应用
  • start a test suite 开始测试套件
    • after each test, invoke a URL on the web app which saves the coverage data to some file named after the test which has just been run, and resets the coverage data 每次测试后,调用Web应用程序上的URL,该URL将coverage数据保存到以刚刚运行的测试命名的文件中,并重置coverage数据
  • after the test suite, generate a cobertura report for every saved file. 在测试套件之后,为每个保存的文件生成一个cobertura报告。 Each report will tell which code has been run by the test 每个报告将告诉测试已经运行了哪些代码

If you need a merged report, I guess it shouldn't be too hard to generate it from the set of saved files, using the cobertura API. 如果您需要合并的报告,我想使用cobertura API从保存的文件集生成报告应该不会太难。

Your proposed solution seems like a reasonable one, except for the proposed solution to relate the test and request by timing. 您提出的解决方案似乎是一个合理的解决方案,除了提出的解决方案按时间将测试和请求相关联。 I've tried to do this sort of thing before, and it works. 我以前尝试过做这种事情,并且它有效。 Most of the time. 大多数时候。 Unless you write your JUnit code very carefully, you'll have lots of issues, because of differences in time between the two machines, or if you've only got one machine, just matching one time against another. 除非您非常仔细地编写JUnit代码,否则,由于两台计算机之间的时间差异,或者如果您只有一台计算机,而一次匹配另一台计算机,则会遇到很多问题。

A better solution would be to implement a Tomcat Valve which you can insert into the lifecycle in the server.xml for your webapp. 更好的解决方案是实现Tomcat Valve ,您可以将其插入Webapp的server.xml的生命周期中。 Valves have the advantage that you define them in the server.xml, so you're not touching the webapp at all. Valve的优势在于您可以在server.xml中定义它们,因此您完全不需要接触Web应用程序。

You will need to implement invoke(). 您将需要实现invoke()。 The best place to start is probably with AccessLogValve . 最好的起点可能是AccessLogValve This is the implementation in AccessLogValve: 这是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);       
}

All this does is log the fact that you've accessed it. 所有这一切都记录您已访问它的事实。

You would implement a new Valve. 您将实施一个新的Valve。 For your requests you pass a unique id as a parameter for the URL, which is used to identify the tests that you're running. 对于您的请求,您传递唯一的ID作为URL的参数,该ID用于标识您正在运行的测试。 Your valve would do all of the heavy lifting before and after the invoke(). 您的阀门将在invoke()之前和之后进行所有繁重的工作。 You could remove remove the unique parameter for the getNext().invoke() if needed. 如果需要,可以删除删除getNext()。invoke()的唯一参数。

To measure the coverage, you could use a coverage tool as suggested by JB Nizet, based on the unique id that you're passing over. 要衡量覆盖率,您可以根据传递的唯一ID,使用JB Nizet建议的覆盖率工具。

So, from junit, if your original call was 因此,如果您最初的电话是

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

You would change this to be: 您可以将其更改为:

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

Then you'd pick up the parameter testId in your valve. 然后,您将在阀中选取参数testId。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM