You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java正则提取测试方法中STARTING与ENDING间的代码?

提取Java测试方法中指定日志间的代码实现方案

一、正则修正方案(适用于格式规整的代码)

如果你的代码格式比较统一(比如日志语句单独成行,没有嵌套的同名日志内容),可以用修正后的正则来匹配。先看典型的测试类代码示例:

public class TestDemo {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestDemo.class);

    @Test
    public void testLogin() {
        LOGGER.info("STARTING TEST CASE : testLogin");
        // 业务代码段
        User user = new User("admin", "123456");
        boolean result = userService.login(user);
        assertTrue(result);
        LOGGER.info("ENDING TEST CASE: testLogin");
    }

    @Test
    public void testQuery() {
        LOGGER.info("STARTING TEST CASE : testQuery");
        // 另一段业务代码
        List<Order> orders = orderService.queryByUserId(1);
        assertFalse(orders.isEmpty());
        LOGGER.info("ENDING TEST CASE: testQuery");
    }
}

之前的正则失效大概率是没处理多行匹配或用了贪婪模式,修正后的实现代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexCodeExtractor {
    public static List<String> getTestCodeSegments(String javaFileContent) {
        List<String> codeList = new ArrayList<>();
        // 正则规则:匹配START日志到END日志之间的内容,支持多行,非贪婪匹配
        String regex = "LOGGER\\.info\\(\"STARTING TEST CASE : .*?\"\\);\\s*(.*?)\\s*LOGGER\\.info\\(\"ENDING TEST CASE: .*?\"\\);";
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL | Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(javaFileContent);
        
        while (matcher.find()) {
            String segment = matcher.group(1).trim();
            if (!segment.isEmpty()) {
                codeList.add(segment);
            }
        }
        return codeList;
    }
}

关键注意点:

  • 加Pattern.DOTALL让.能匹配换行符,支持跨多行的代码段
  • 用.*?非贪婪匹配,避免一次性匹配多个测试方法的内容
  • 要保证日志语句的格式和正则完全匹配(比如引号、空格、冒号的位置不能错)

二、Java语法解析方案(更可靠,适配复杂代码)

正则处理Java代码容易踩坑(比如嵌套方法、字符串里包含类似日志的内容、多行注释干扰),用专业的Java语法解析器(比如JavaParser)是更稳妥的选择:

  1. 先引入JavaParser依赖(Maven):
<dependency>
    <groupId>com.github.javaparser</groupId>
    <artifactId>javaparser-core</artifactId>
    <version>3.25.8</version>
</dependency>
  1. 实现提取逻辑:
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ParserCodeExtractor {
    public static List<String> extractTestCode(File javaTestFile) throws IOException {
        List<String> codeSegments = new ArrayList<>();
        CompilationUnit cu = JavaParser.parse(javaTestFile);
        
        // 遍历所有方法,筛选测试方法并提取目标代码
        new VoidVisitorAdapter<Void>() {
            @Override
            public void visit(MethodDeclaration method, Void arg) {
                super.visit(method, arg);
                // 只处理带@Test注解的测试方法
                if (method.getAnnotationByName("Test").isPresent()) {
                    List<Statement> statements = method.getBody().get().getStatements();
                    boolean isInTargetBlock = false;
                    StringBuilder codeSb = new StringBuilder();
                    
                    for (Statement stmt : statements) {
                        // 判断是否是START/END日志语句
                        if (stmt.isExpressionStmt() && stmt.asExpressionStmt().getExpression().isMethodCallExpr()) {
                            MethodCallExpr logCall = stmt.asExpressionStmt().getExpression().asMethodCallExpr();
                            if (logCall.getName().asString().equals("info") 
                                && logCall.getScope().isPresent() 
                                && logCall.getScope().get().asName().asString().equals("LOGGER")) {
                                
                                String logContent = logCall.getArguments().get(0).asStringLiteralExpr().getValue();
                                if (logContent.startsWith("STARTING TEST CASE :")) {
                                    isInTargetBlock = true;
                                    continue;
                                }
                                if (logContent.startsWith("ENDING TEST CASE:")) {
                                    isInTargetBlock = false;
                                    if (codeSb.length() > 0) {
                                        codeSegments.add(codeSb.toString().trim());
                                        codeSb.setLength(0);
                                    }
                                    continue;
                                }
                            }
                        }
                        // 处于目标区间内时,拼接代码
                        if (isInTargetBlock) {
                            codeSb.append(stmt.toString()).append("\n");
                        }
                    }
                }
            }
        }.visit(cu, null);
        
        return codeSegments;
    }
}

这个方案的优势:

  • 精准识别Java语法结构,不会被字符串、注释里的干扰内容误导
  • 可以精准过滤带@Test注解的测试方法
  • 支持复杂代码结构(比如嵌套if、循环、多行代码)

三、正则失效的常见原因排查

如果之前的正则没生效,大概率是这几个问题:

  • 没加Pattern.DOTALL,导致.无法匹配换行符,跨多行的代码段匹配不到
  • 用了贪婪匹配.*,导致一次性匹配了多个测试方法的内容
  • 日志语句的格式和正则不匹配(比如多了空格、引号用了单引号、冒号位置不对)

内容的提问来源于stack exchange,提问作者Psl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:29:51