我有一个相当复杂的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()不是静态的。
有什么想法吗?
答案 0 :(得分:1)
我创建了一个关于如何测试ANTLR访问者的示例项目(使用Mockito&amp; TestNG)。 The full source code can be found on 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
方法的实现)。
答案 1 :(得分:0)
反思可能是正确答案:
Method method = MyParser.class.getDeclaredMethod("qux");
ParseTree tree = (ParseTree) method.invoke(parser);
适合替代:
ParseTree tree = parser.qux();