15

この新しいJava7のtry-with-resourcesコンストラクトは非常に優れています。または少なくとも、例外が発生して私の一日を台無しにするまで良かったです。

私はついにそれをJUnit+jMockだけを使用する再現可能なテストに要約することができました。

@Test
public void testAddSuppressedIssue() throws Exception {
    Mockery mockery = new Mockery();
    final Dependency dependency = mockery.mock(Dependency.class);

    mockery.checking(new Expectations() {{
        allowing(dependency).expectedCall();
        allowing(dependency).close();
    }});

    try (DependencyUser user = new DependencyUser(dependency)) {
        user.doStuff();
    }
}

// A class we're testing.
private static class DependencyUser implements Closeable {
    private final Dependency dependency;

    private DependencyUser(Dependency dependency) {
        this.dependency = dependency;
    }

    public void doStuff() {
        dependency.unexpectedCall(); // bug
    }

    @Override
    public void close() throws IOException {
        dependency.close();
    }
}

// Interface for its dependent component.
private static interface Dependency extends Closeable {
    void expectedCall();
    void unexpectedCall();
}

この例を実行すると、次のようになります。

java.lang.IllegalArgumentException: Self-suppression not permitted
    at java.lang.Throwable.addSuppressed(Throwable.java:1042)
    at com.acme.Java7FeaturesTest.testTryWithResources(Java7FeaturesTest.java:35)

ドキュメントを読むと、抑制された例外をそれ自体に追加し直すと、それがこのエラーのトリガーになると言われているようです。しかし、私はそれをしていません。try-with-resourcesブロックを使用しているだけです。次に、Javaコンパイラは、違法と思われるコードを生成します。これにより、機能が事実上使用できなくなります。

もちろん、テストに合格すれば問題はありません。また、テストが失敗すると、例外が発生します。これで、最初に発見した問題を修正したので、try-with-resourcesの使用に戻りました。しかし、次に例外が発生したときは、正当な理由がないように見える1つのJava自体が出力するのではなく、期待の失敗が例外になります。

それで...try-with-resourcesをあきらめることなく、ここで適切なエラー報告を取得する方法はありますか?

4

2 に答える 2

7

jMockが両方のメソッドから同じ例外インスタンスをスローするようです。これが、jMockなしで再現できる方法です。

public class Test implements Closeable {
    private RuntimeException ex = new RuntimeException();

    public void doStuff() {
        throw ex;
    }

    public void close() {
        throw ex;
    }
}

try (Test t = new Test()) {
    t.doStuff();
}

もしそうなら、それはJavaコンパイラではなくjMockの問題だと思います。

于 2012-08-24T05:51:08.490 に答える
0

Apache Commons VFSで問題が発生しました(Java 8でユニットテストが失敗しました。VFS-521を参照してください)。そして、java.io.FilterOutputStreamは、同じ例外をスローするflush + closeを処理できない方法で、try-with-resource(抑制された例外)機能を使用していることがわかりました。

さらに悪いことに、Java 8より前では、flush()呼び出しからの例外を黙って飲み込んでいます。JDK-6335274を参照してください)。

super.close()をまったく避けて修正しました。現在、corelibs-dev openjdk mailingl istでこれについて議論しています:http://openjdk.5641.n7.nabble.com/FilterOutputStream-close-throws-exception-from-flush-td187617.html

于 2014-05-02T23:13:36.833 に答える