测试antlr4访问者规则



我有一个相当复杂的antlr4语法,它利用了访问者模式。我想测试访客的某些部位。测试个人访问规则的好方法是什么?

我的访问者有很多这样的规则,我想测试一下:

@Override
public Object visitQux(ExclParser.QuxContext ctx) {
  return visitChildren(ctx);
}

我的测试代码基本如下:

PrintStream ps = new PrintStream(stdError, false /* autoFlush */, "UTF-8")
ANTLRInputStream input = new ANTLRInputStream(is);
MyLexer lexer = new MyLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
MyParser parser = new MyParser(tokens);
parser.removeErrorListeners();
MyErrorListener errorListener = new MyErrorListener(ps, filename);
parser.addErrorListener(errorListener);
MyVisitor visitor = new MyVisitor();
visitor.setParser(filename, parser, errorListener);
ParseTree tree = parser.qux();   // <--- This is the line I want to vary.
Object result = visitor.visit(tree);
assertThat(describeExpectation(), result, equalTo(this.expectedOutput));

理想情况下,我将能够使用参数化测试测试任何访问者。但是为了获得我想访问的解析树(parser.qux),我不能在表中指定qux()的任何变体,因为parser.qux()不是静态的。

任何想法吗?

我创建了一个关于如何测试antlr访问者的示例项目(使用mockitotestng)。完整的源代码可以在GitHub上找到。以下是最重要的部分:

public class MyVisitor extends DemoBaseVisitor<String> {
    @Override
    public String visitPlus(final DemoParser.PlusContext ctx) {
        return visit(ctx.left) + " PLUS " + visit(ctx.right);
    }
    @Override
    public String visitLiteralNumber(final DemoParser.LiteralNumberContext ctx) {
        return ctx.getText();
    }
}

任何我对访问者的测试:

public class MyVisitorTest {
    private final MyVisitor myVisitor = new MyVisitor();
    @Test
    public void visitPlus_joinsOperatorsWithWordPLUSAsSeparator() throws Exception {
        // setup
        final DemoParser.PlusContext plusNode = mock(DemoParser.PlusContext.class);
        plusNode.left = mockForVisitorResult(DemoParser.ExpressionContext.class, "2");
        plusNode.right = mockForVisitorResult(DemoParser.ExpressionContext.class, "4");
        // execution
        final String actual = myVisitor.visitPlus(plusNode);
        // evaluation
        assertEquals(actual, "2 PLUS 4");
    }
    private<T extends RuleContext> T mockForVisitorResult(final Class<T> nodeType, final String visitResult) {
        final T mock = mock(nodeType);
        when(mock.accept(myVisitor)).thenReturn(visitResult);
        return mock;
    }
    @Test
    public void visitLiteralNumber_returnsTextValueOfNumber() throws Exception {
        // setup
        final DemoParser.LiteralNumberContext literalNumberNode = mock(DemoParser.LiteralNumberContext.class);
        when(literalNumberNode.getText()).thenReturn("42");
        // execution
        final String actual = myVisitor.visitLiteralNumber(literalNumberNode);
        // evaluation
        assertEquals(actual, "42");
    }
}

在您的特殊示例中,您有一个调用visitChildren()的方法,您将测试调用该方法返回访问所有子节点的聚合结果(聚合是什么取决于您对aggregateResult方法的实现)。

反射可能是正确的答案:

Method method = MyParser.class.getDeclaredMethod("qux");
ParseTree tree = (ParseTree) method.invoke(parser);

适合替换:

ParseTree tree = parser.qux();

相关内容

  • 没有找到相关文章

最新更新