2

状況はまったく異なりますが、同じ問題のように思われる2つのケースがあります。

1)データベースへのオブジェクトの読み取りと書き込みの両方をテストしています。毎回オブジェクトをクリーンアップして再構築しているので、書き込みテストは各フィールドの書き込みを確認するために読み取る必要があり、読み取りテストは最初に書き込みを行うため、テストは同じように見えます。それでも、インターフェイスの主要なメソッドをテストせずに残したくありません。

2)はるかに小さなケースでは、小さなデータオブジェクトに対してcopy()メソッドとequals()メソッドをテストしています。copy()メソッドはequals()を使用してそれ自体をテストし、equals()メソッドはコピーに対してテストします。繰り返しますが、テストは複製されます。

ここで何かが足りないように感じます。余分な作業を大量に作成せずに依存関係を分離する方法(生のJDBCをデータベースに書き込むなど)この種のテストの重複に対処する標準的な方法はありますか? ?

4

2 に答える 2

1

表面的なテストとして、あなたがしていることは問題ありません。結局のところ、あなたがしたいのは、writeメソッドとreadメソッドが相補的であると主張することです。書き込みと読み取りを行うと、等しいオブジェクトが得られます(コピーと等しい場合も同じです)。残念ながら、私はしません。あなたがすでに知っているように、あなたは余分な仕事なしでより深く行くことができると思います。テストは非常に単純であるため、追加のテストは必要ありません。また、書き込みと読み取りの2番目の実装を作成しない限り、手動で作業する必要があります。

于 2011-11-02T23:07:05.473 に答える
1

私にとって、この種のテストはコードの臭いです。問題は常にです:このテストは正確に何をテストしますか?このテストでは、何を信頼し、何を信頼しませんか?

私にとって、read()とwrite()を一緒に信頼することはできません。これらはおそらく同じクラスにあり、同じ人によって書かれています。したがって、write()を呼び出してread()をテストしている場合、これは適切なテストではありません。write()とread()が同期していることをテストしているのであって、本来の動作をしているわけではありません。

2番目の例では、copyとequalsが同期していることをテストしていますが、同じ問題です。

これが永続層の実装だったとしましょう。

public class PersistenceLayer {
    private Object object;

    void write(Object object) {
        this.object = object;
    }

    Object read(Long id) {
        return object;
    }
}

問題は、この永続層でテストに合格するかどうかです。しかし、それは明らかにあなたが望むことをしません。データベースには近づきません。同様に、読み取りと書き込みでセッション/トランザクションを共有した場合、テストは合格しますか?この場合、データが実際にデータベースにコミットされることはありません。最後にロールバックを行う場合があります。しかし、あなたのテストはまだ合格します。

説明を読んで、write()を呼び出してからread()を呼び出すと、同様のオブジェクトが返されることをテストしています。write()メソッドに期待するのは、データベースにデータを書き込むことです。したがって、それをテストしている場合は、それを確認する必要があります。したがって、読み取りと書き込みをテストするために使用できる別のチャネルが必要です。これは通常、JDBCを介して新しい接続を作成し、選択を実行することになります。

だから私のテストコードは

testWrite() {
    write(o);
    Object o2 = readByJdbc("SELECT * FROM table WHERE id = ?", o);
    assertObjectsEqual(o, o2); // this needs to compare all values
}

testRead() {
    write(o);
    Object o2 = read(o.id);
    Object o3 = readByJdbc("SELECT * FROM table WHERE id = ?", o);

    assertObjectsEqual(o2, o3); // this needs to compare all values
}

testWrite()はデータベースに書き込み、JDBC接続を開いてその方法で読み取ることにより、データがデータベースに書き込まれるようにします(異なるセッション、異なるトランザクション、つまりデータはデータベースにあります)。

testRead()はデータベースに書き込み、永続層とjdbcを介した読み取りによって返された2つのオブジェクトを比較します。write(o)の呼び出しを複製していますが、他のテストが呼び出されたときにwriteが機能するかどうかがわかっているので、許容できます。別のwriteByJdbcを作成することもできますが、2つではなく1つのテストが失敗するだけです。

実際、パラノイアのレベルによっては、assertObjectsEqual()のすべての値を比較する必要はありません。たとえば、Hibernateを使用している場合は、すべてが正しく宣言されていると想定し、データベースに行が存在するかどうかをテストできます。私は休止状態を信頼しているので、これを頻繁に行います。ただし、その場合は、Hibernateの呼び出し方法、オブジェクトの定義方法をテストする必要があります。

jdbcコードは長くて複雑である必要はありません。単純な選択のために、列から値へのマップのリストを作成するだけです。

private List<Map<String, Object>> resultSetToListMap(ResultSet resultSet) throws SQLException {
    int columnCount = resultSet.getMetaData().getColumnCount();
    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

    while (resultSet.next()) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();

        for (int i = 1; i <= columnCount; i++) {
            map.put(resultSet.getMetaData().getColumnName(i), resultSet.getObject(i));
        }

        list.add(map);
    }

    return list;
}

これは、ほとんどのテストには十分すぎるほどです。

于 2011-11-03T08:22:36.287 に答える