0

ビジター パターンを利用するかなり複雑な 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) を取得するために、parser.qux() は静的ではないため、テーブルで qux() のバリアントを指定できません。

何かご意見は?

4

2 に答える 2

1

ANTLR 訪問者をテストする方法 (Mockito&TestNG を使用) に関するサンプル プロジェクトを作成しました。完全なソース コードは 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メソッドの実装によって異なります)。

于 2015-03-21T15:55:30.650 に答える
0

ここではリフレクションが正しい答えかもしれません。

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

以下の適切な代替品です。

ParseTree tree = parser.qux();
于 2014-06-28T15:20:13.560 に答える