3

私は次の問題を解決しようとしています:

  • 私はJavaアプリ(私が書いたものではありません)を持っています。その目的は2つのレポートファイル(コンマ区切りのテーブル出力)を取得し、ファイルの各行と各列をセルごとに比較することです。基本的に、回帰テスト用です。

  • 次の機能で拡張したいと思います。

    • C1列のすべての値が100%増加するようにソフトウェアを変更したとします。

    • 特定の列「C1」を比較すると、ソフトウェアは現在、C1の値が100%変更されたことを報告します。

    • 私がやりたいのは、単に「row1のC1は両方のファイルで同じである」と比較するのではなく、事前に構成された比較ルール/式をフィールドに適用するように回帰テスターを構成できるようにすることです。ファイル#2のC1値は、ファイル#1のC1値の2倍です。このようにして、すべての行の列C1が一致しないという偽の回帰エラーを100%抑制するだけでなく、新しいソフトウェアを使用して列C1が正確に100%大きくない実際のエラーもキャッチします。

以前にこの種の機能をPerlでコーディングした場合、解決策は非常に単純でした。カスタムの列ごとのコンパレータ構成を構成ファイルに格納されたPerlハッシュにコーディングするだけで、ハッシュキーは列で、ハッシュ値は2つの値を比較するためのPerlサブルーチンです。私が望んでいた複雑な方法。

明らかに、このアプローチはJavaでは機能しません。Javaでカスタムコンパレータロジックを記述できず、Javaで異なる実行時にこれらのコンパレータを評価/コンパイル/実行することができないためです。

これは、私の異なるものが解釈/評価/実行するドメイン固有の解釈可能な言語を考え出す必要があることを意味します。

私はJavaエコシステムとライブラリにあまり詳しくないので、SOに質問しています。

構成可能なコンパレータロジックにこのDSLを実装するための良いソリューションは何でしょうか?

私の要件は次のとおりです。

  • 解決策は「ビールのように無料」でなければなりません

  • ソリューションは「シュリンクラップ」する必要があります。たとえば、既存のライブラリをコードにドロップし、構成ファイルを追加して、機能させることができます。

    独自のBNF文法を作成する必要があり、独自のインタープリターを作成する必要がある汎用文法パーサーを提供するものは受け入れられません。

  • ソリューションは、データの処理と構文が豊富である限り、適度に柔軟である必要があります。例えば:

    • 少なくとも、データの行全体をハッシュとして渡すことができ、DSL内から参照/アドレスを渡すことができるはずです。

    • 適度に完全な構文が必要です。少なくとも基本的な文字列操作(連結、サブ文字列、理想的にはある程度の正規表現の一致と置換)を実行します。abs(val1 - val2) > tolerance浮動小数点#sで実行する機能を含む基本的な算術。条件文や理想的にはループなどの基本的なフロー制御/ロジック。

  • ソリューションは適度に高速で、スケーラブルである必要があります。たとえば、100x100サイズのファイルを比較する場合、10〜20のカスタム列で10分かかることはありません。

重要な場合、ターゲット環境はJava1.6です。

4

3 に答える 3

4

多くの労力をかけずにJavaアプリケーションに簡単に統合できる複数の動的JVMプログラミング言語があります。GroovyScalaを調べる価値があると思います。

もう1つの可能なオプションは、XTextまたはXTendを使用して独自のDSLを作成することです。

于 2012-08-10T20:42:35.970 に答える
3

Java の動的機能となると、魅力的なランタイムおよびメモリー内コンパイラーである Janino を思いつきます。あなたの場合、プレーンJavaの eval(...) に似たものが得られます。http://docs.codehaus.org/display/JANINO/Basic#Basic-expressionevaluatorを参照してください。

ここでのポイントは、テスト構成用の DSL はありませんが、プレーンな Java 構文を使用してテスト構成にカスタム式を記述できるということです。

以下に提案するソリューションでは満たされない唯一の要件は、構成ファイル内から行全体をアドレス指定できることです。このソリューションでは、テスト データを値ごと (またはより良いペアごと) に反復処理し、構成済みの式を使用して単一の値を比較する Java テスト クラスを作成することを前提としています。したがって、動的部分は式であり、静的部分はテストデータの反復です。

ただし、以下に示すように、必要なコードは非常に小さく単純です。

構成ファイル (Java プロパティの構文、キーは列名、値はテスト式):

# custom expression for column C1
C1  = a == 2 * b           
# custom expression for column C4
C4  = a == b ^ 2           
# custom expression for column C47
C47 = Math.abs(a - b) < 1  

テストコードのスケッチ:

// read config file into Properties
Properties expressions = Properties.load(....);

// Compile expressions, this could also be done lazily
HashMap<String, ExpressionEvaluator> evals = new HashMap<String, ExpressionEvaluator>();
for (String column : expressions.stringPropertyNames()) {
    String expression = expressions.getProperty(column);
    ExpressionEvaluator eval = new ExpressionEvaluator(
        expression,                  // expression
        boolean.class,               // expressionType
        new String[] { "a", "b" },   // parameterNames
        new Class[] { int.class, int.class } // parameterTypes, depends on your data
    );
    evals.put(column, eval);
}

// Now for every value pair (a, b) check if a custom expression is defined 
// for the according column and if yes execute: 
Boolean correct = (Boolean) theEvalForTheColumn.evaluate(
    new Object[] { a, b }          // parameterValues
);
if (!correct) throw Exception("Wrong values...");

Janino のページで述べたように、コンパイルされた式のパフォーマンスはかなり良好です (これらは実際の Java バイト コードです)。コンパイルだけがプロセスを遅くします。そのため、多くのカスタム式がある場合は問題になる可能性がありますが、値の数が増えると適切にスケーリングされるはずです。h番目。

于 2012-08-10T22:56:43.860 に答える
0

組み込み言語は必要ありません。コンパレーターをインターフェースとして定義します。

class.forName(name) を使用して、実行時にインターフェイスを定義するクラスをロードできます。この名前は、コマンド ライン引数またはその他の便利な方法で指定できます。

あなたのコンパレータクラスは次のようになります

class SpecialColumn3 implements ColumnCompare
{ boolean compare(String a,String b) {...}
}
于 2012-08-10T23:10:19.803 に答える