web-dev-qa-db-ja.com

Java十分に活用されていないアサーション

assertキーワードがJavaであまり使用されていないのはなぜでしょうか。私はそれらが使用されるのを見たことがほとんどありませんが、私はそれらが素晴らしいアイデアだと思います。私は確かに以下の簡潔さを好みます:

assert param != null : "Param cannot be null";

冗長性:

if (param == null) {
    throw new IllegalArgumentException("Param cannot be null");
}

私の疑いは、それらが活用されていないためです

  • 彼らは比較的遅れて到着し(Java 1.4)、その頃には多くの人々がすでにJavaプログラミングスタイル/習慣を確立していた
  • デフォルトでは実行時にオフになっています
66
Dónal

assertionsは、理論的には、テスト用 invariants であり、mustコードが適切に完了するためには、trueである必要があります。

示されている例は、有効な入力のテストです。これは、一般にユーザー指定であるため、アサーションの一般的な使用法ではありません。

オーバーヘッドがあり、不変条件が失敗する状況は、開発およびテスト中にコーディングエラーとしてキャッチされたと想定されるため、アサーションは一般に製品コードでは使用されません。

彼らがJava)に「遅れて」来ることについてのあなたのポイントは、彼らがより広く見られない理由でもあります。

また、ユニットテストフレームワークでは、プログラムによるアサーションの必要性の一部をテスト対象のコードの外部にすることができます。

61
Ken Gentle

ユーザー入力をテストするためにアサーションを使用することはアサーションの乱用です。無効な入力に対してIllegalArgumentExceptionをスローすると、呼び出しメソッドが例外をキャッチし、エラーを表示して、必要な処理をすべて実行できるため(入力の再要求、終了など)、より正確です。

そのメソッドがクラス内のプライベートメソッドである場合、誤ってnull引数を渡していないことを確認しようとしているだけなので、アサーションは問題ありません。アサーションをオンにしてテストし、すべてのパスをテストし、アサーションをトリガーしていない場合は、パスをオフにして、リソースを無駄にしないようにすることができます。コメントとしても役立ちます。メソッドの最初のassertは、特定の前提条件に従う必要があることをメンテナーに示す適切なドキュメントであり、後置条件の最後のassertは、メソッドが何をすべきかを文書化します。コメントと同じくらい便利です。さらに、アサーションをオンにすると、実際に文書化した内容をテストします。

アサーションはテスト/デバッグ用であり、エラーチェックではありません。これがデフォルトでオフになっている理由です。ユーザー入力を検証するためにアサーションを使用するのを防ぐためです。

56
Adam Jaskiewicz

「Effective Java」では、Joshua Blochが(「パラメーターの妥当性の確認」トピックで)採用する単純なルールのような)パブリックメソッドについては、引数を検証し、無効な場合は必要な例外をスローすることを提案しました。非公開メソッド(公開されておらず、ユーザーとしての有効性を保証する必要がある)の場合は、代わりにアサーションを使用できます。

yc

18
yclian

From アサーションを使用したプログラミング

デフォルトでは、アサーションは実行時に無効になっています。 2つのコマンドラインスイッチを使用すると、アサーションを選択的に有効または無効にできます。

これは、ランタイム環境を完全に制御できない場合、アサーションコードが呼び出されることさえ保証できないことを意味します。アサーションは、本番用コードではなく、テスト環境で使用するためのものです。ユーザーがアサーションを無効にしてアプリケーションを実行すると(default)、すべてのエラー処理コードが消えるため、例外処理をアサーションに置き換えることはできません。

18
Bill the Lizard

@ドン、アサーションがデフォルトでオフになっていることにイライラしています。私もそうでしたので、インライン化するこの小さなjavacプラグインを作成しました(つまり、このばかげたアサートバイトコードではなく、if (!expr) throw Exのバイトコードを発行します)。

Javaコードをコンパイルしているときに、クラスパスに fa.jar を含めると、魔法がかかり、

Note: %n assertions inlined.

@see http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions またはgithub https://github.com/akuhn/javac

9
akuhn

アサーションは次の理由で役立ちます。

  • プログラミングエラーを早期にキャッチ
  • コードを使用したドキュメントコード

それらをコードの自己検証と考えてください。失敗した場合は、プログラムが壊れており、停止する必要があることを意味します。ユニットテスト中は常にそれらをオンにしてください!

The Pragmatic Programmer では、本番環境で実行することを推奨しています。

アサーションをオンのままにする

アサーションを使用して不可能を防ぐ。

アサーションは失敗するとAssertionErrorをスローするため、catch Exceptionでキャッチされないことに注意してください。

2

なぜわざわざアサーションを書いて標準のif then条件ステートメントに置き換えるのかわからないのですが、そもそもifsとして条件を書いてみませんか?

アサートはテスト専用であり、2つの副作用があります。大きなバイナリと有効にするとパフォーマンスが低下します(そのため、これらをオフにできます!)

条件を検証するためにアサートを使用しないでください。これは、アサートが有効/無効になっているときの実行時のアプリの動作が異なることを意味します。これは悪夢です。

2
Nimbus

アサーションは非常に制限されています。ブール条件のみをテストでき、有用なエラーメッセージのコードを毎回作成する必要があります。これを、JUnitのassertEquals()と比較してください。これにより、入力から有用なエラーメッセージを生成し、2つの入力をIDE= JUnitランナーで並べて表示することもできます。

また、これまでに見たIDEでアサーションを検索することはできませんが、すべてのIDEはメソッド呼び出しを検索できます。

1
Aaron Digulla

tl; dr

  • はい、本番環境でアサーションテストを使用します
  • 他のライブラリを使用する( JUnitAssertJHamcrest など。)必要に応じて、組み込みのassert機能ではなく。

このページの他の回答のほとんどは、格言「アサーションは通常、プロダクションコードでは使用されない」をプッシュします。ワープロやスプレッドシートなどの生産性アプリでは真実ですが、Javaが非常に一般的に使用されているため、本番環境でのアサーションテストは非常に便利で一般的です。

プログラミングの世界における多くの格言のように、ある状況で真に始まるものは誤って解釈され、他の状況では誤って適用されます。

生産性アプリ

「アサーションは通常、製品コードでは使用されません」という格言は一般的ですが、正しくありません。

形式化されたアサーションテストは、 Microsoft Word のようなワープロや Microsoft Excel のようなスプレッドシートなどのアプリから始まりました。これらのアプリは、ユーザーが作成した一連のアサーションテストアサーションキーストロークごとを呼び出す可能性があります。そのような極端な繰り返しはパフォーマンスに深刻な影響を与えました。したがって、限られたディストリビューションでのそのような製品のベータ版のみがアサーションを有効にしていました。したがって、格言。

ビジネスアプリ

対照的に、データ入力、データベース、またはその他のデータ処理のためのビジネス指向のアプリでは、本番環境でのアサーションテストの使用は非常に便利です。パフォーマンスへの影響が少ないため、非常に実用的で一般的です。

ビジネスルールをテストする

本番環境で実行時にビジネスルールを検証することは完全に合理的であり、推奨されます。例えば:

  • 請求書に常に1つ以上のラインアイテムが必要な場合は、請求書ラインアイテムの数がゼロより大きいことを確認するアサーションテストを記述します。
  • 製品名が3文字以上である必要がある場合は、文字列の長さをテストするアサーションを記述します。
  • 現金元帳の残高を計算するとき、結果が負になることは決してないことがわかっているので、データまたはコードの欠陥を示す負の数のチェックを実行します。

このようなテストは、本番環境のパフォーマンスに大きな影響を与えません。

ランタイム条件

アプリが本番環境で実行されるときに特定の条件が常に真であると予想する場合は、それらの予想をアサーションテストとしてコードに記述します。

これらの条件が適度に失敗することが予想される場合は、アサーションテストをnot書き込みます。おそらく特定の例外をスローします。その後、可能な限り回復してください。

健全性チェック

健全性チェック 本番環境での実行時も完全に妥当であり、推奨されます。いくつかの奇妙な出来事が起こったときに、数え切れないほどの状況で私の真実が真実であるとは想像できなかったいくつかの任意の条件をテストすることで救いました。

たとえば、ニッケル(0.05)をペニーに丸めることで特定のライブラリにニッケル(0.05)が生成されることをテストしたところ、浮動小数点テクノロジーの欠陥を最初に発見した人の1人になりましたApple PowerPCからIntelへの移行中に Rosetta ライブラリで出荷されます。そのような欠陥が一般に到達することは不可能に思われたでしょう。しかし驚くべきことに、この欠陥は、元のベンダーであるTransitive、およびAppleの通知、およびAppleのベータ版でテストしている早期アクセスの開発者からの通知を免れました。

(ちなみに、私は言及する必要があります... お金の浮動小数点 を使用しないでください BigDecimal を使用してください)

フレームワークの選択

組み込みのassert機能を使用するのではなく、別のアサーションフレームワークを使用することを検討してください。次のような複数のオプションがあります。

またはあなた自身のロール。プロジェクトで使用する小さなクラスを作成します。このようなもの。

package work.basil.example;

public class Assertions {
    static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws Java.lang.AssertionError {
        if ( booleanExpression ) {
            // No code needed here.
        } else { // If booleanExpression is false rather than expected true, throw assertion error.
            // FIXME: Add logging.
            throw new Java.lang.AssertionError( message.toString() );
        }
    }

}

使用例:

Assertions.assertTrue( 
    localTime.isBefore( LocalTime.NOON ) , 
    "The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d." 
) ;

あなたの質問

彼らは比較的遅れて到着し(Java 1.4)、その頃には多くの人々がすでにJavaプログラミングスタイル/習慣を確立していた

はい、そうです。多くの人々は、Sun/JCPが表明テストのために開発したAPIに失望しました。その設計は、既存のライブラリと比較して光沢がありませんでした。そのため、多くの人が新しいAPIを無視し、既知のツール(サードパーティツール、または独自のミニライブラリ)を使用していました。

デフォルトでは実行時にオフになっていますが、なぜOHなのですか?

最初の数年間、Javaはパフォーマンスの速度が遅いために不適切なラップを得ました。皮肉なことに、 Javaは急速に進化しました パフォーマンスにとって最高のプラットフォームの1つになりました。しかし、悪いラップは臭い臭いのようにぶらぶらしました。そのため、Sunは、測定可能な方法でパフォーマンスに影響を与える可能性のあるものについては非常に警戒していました。したがって、この観点では、アサーションテストの無効化をデフォルトにすることが理にかなっています。

デフォルトで無効にするもう1つの理由は、新しいアサーション機能を追加する際に、SunがWordのassertをハイジャックしたという事実に関連している可能性があります。これは以前は予約されていたキーワードでありnotであり、Java言語に対してこれまでに行われたいくつかの変更の1つが必要でした。メソッド名assertは、多くのライブラリや多くの開発者が独自のコードで使用していました。この歴史的な移行についての議論については、この古いドキュメント アサーションを使用したプログラミング をお読みください。

1
Basil Bourque

他の人が述べたように:アサーションはユーザー入力の検証には適切ではありません。

冗長性が気になる場合は、私が書いたライブラリ https://bitbucket.org/cowwoc/requirements/ をチェックすることをお勧めします。非常に小さなコードを使用してこれらのチェックを表現でき、ユーザーに代わってエラーメッセージを生成します。

requireThat("name", value).isNotNull();

アサーションの使用を主張する場合は、これも行うことができます。

assertThat("name", value).isNotNull();

出力は次のようになります。

Java.lang.NullPointerException: name may not be null
0
Gili

実際、彼らはJava 1.4

主な問題は、EclipseまたはJ2EEサーバーのように、jvmオプションを自分で直接管理しない環境でコーディングする場合です(どちらの場合も、jvmオプションを変更することはできますが、どこにあるかを深く検索する必要があります) ifと例外を使用する方が簡単です(つまり、必要な労力が少ないことを意味します)。

0
Denis R.