質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.90%

Javaのアサーションと単体テストについて

解決済

回答 3

投稿

  • 評価
  • クリップ 2
  • VIEW 3,443
退会済みユーザー

退会済みユーザー

Javaのアサーションと単体テストについての質問です。
ある入力値に対してその戻り値が目的の結果となるかを確認するテストにアサーションは向きません。
さらに、アサーションを用いるとコードは当然のことながら長くなってしまいます。

そうすると、なぜアサーションを用いるのでしょうか。
全てのテストをテストクラスに書いて行った方がよくないですか?
アサーションの意義や有用性はどういったものになるのでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

アサーションの意義や有用性はどういったものになるのでしょうか。

アサーション(assertion)とテスト(test)とでは目的が異なります。また互いに相補的なものですから、両方を記述していくのが好ましいです。

  • アサーション=アルゴリズムや内部処理ステップの正当性を保証すもの。主に不変条件を確認する。
  • テスト=メソッドの外部仕様/外からみた振る舞いを保証するもの。主に事後条件を確認する。

さらに、アサーションを用いるとコードは当然のことながら長くなってしまいます。 

アルゴリズムや内部処理の区切りに、不変条件を確認するassert文を配置する程度であれば、コードの肥大化を気にする必要はないと思います。アサーションにより得られる正当性の保証は、ソースコードが多少間延びするデメリットを大きく上回るはずです。

Javaのアサーション(assert文)については、下記サイトが参考になります:


そもそもメソッドの引数チェックってするものなのでしょうか。

するものです。

重要なメソッドだったら、引数チェックの必要があり、assertを使うと無効にされる恐れがあるから、ちゃんとしたチェックにしろ、という意味でしょうか。

外部公開する(≒publicな)メソッドでは、常に引数チェックを行うべきです。assert文は無効化される可能性もあるため、外部メソッドの引数チェックとしては不適切です。

もし、そうだとすれば、なぜpublicでないメソッドの方はassetionで良いということになるのでしょうか。

引数チェックのようなメソッドの事前条件チェックは、クラス内部(自分)とその外部(他人)の責任分界点を明確化したうえで行う、防衛的プログラミングの一種です。publicでないメソッドは、呼び出し元も自分の責任ですから、assertionでも十分という判断になります(もちろん、publicメソッド同様に引数チェックしてもよいです)。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/17 14:11

    事前条件
    規約により、public メソッドの事前条件は、特定の指定された例外をスローする明示的なチェックによって適用されます。たとえば、

    /**
    * Sets the refresh rate.
    *
    * @param rate refresh rate, in frames per second.
    * @throws IllegalArgumentException if rate <= 0 or
    * rate > MAX_REFRESH_RATE.
    */
    public void setRefreshRate(int rate) {
    // Enforce specified precondition in public method
    if (rate <= 0 || rate > MAX_REFRESH_RATE)
    throw new IllegalArgumentException("Illegal rate: " + rate);
    setRefreshInterval(1000/rate);
    }
    この規約は、assert 構文を追加しても影響を受けません。public メソッドのパラメータのチェックにはアサーションを使用しないでください。public メソッドは、常に引数チェックを適用することを保証するので、assert は適していません。public メソッドは、アサーションが有効かどうかにかかわらず引数をチェックする必要があります。さらに、assert 構文は、指定した種類の例外をスローしません。assert 構文がスローできるのは、AssertionError のみです。

    ただし、クライアントがクラスを使用して行う処理の内容にかかわらず true になることがわかっている public ではないメソッドの事前条件については、アサーションを使用してその事前条件をテストできます。たとえば、前述のメソッドによって呼び出される次の「ヘルパーメソッド」内ではアサーションの使用が適しています。

    /**
    * Sets the refresh interval (which must correspond to a legal frame rate).
    *
    * @param interval refresh interval in milliseconds.
    */
    private void setRefreshInterval(int interval) {
    // Confirm adherence to precondition in nonpublic method
    assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval;

    ... // Set the refresh interval
    }

    回答ありがとうございます。
    上を要約すると、publicが付いていたら、asserによる事前チェックはするな
    publicが付いていなくて、確実にtrueが返ってくるならば、assertによる事前チェックをしても良い

    というような内容になると思うのですが、理由がよく理解できませんでした。
    「public メソッドは、常に引数チェックを適用することを保証するので、assert は適していません。public メソッドは、アサーションが有効かどうかにかかわらず引数をチェックする必要があります。」

    そもそもメソッドの引数チェックってするものなのでしょうか。
    重要なメソッドだったら、引数チェックの必要があり、assertを使うと無効にされる恐れがあるから、ちゃんとしたチェックにしろ、という意味でしょうか。
    もし、そうだとすれば、なぜpublicでないメソッドの方はassetionで良いということになるのでしょうか。

    キャンセル

+2

アサーションのメリットとしては、「動作の途中で状態チェックをできる」ということがあります。テストメソッドではメソッド単位以上の粒度で動作検証を行うことはできませんが、アサーションであれば、「この行でこの条件を満たす」ということを検証できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

Java標準のアサーションはデバッグ用であり、テスト用コードではありません。

今でこそJUnitやテストファーストの考え方があるのでクラスの単体テストを記述できる文化が浸透していますので意味はありませんが、導入される前は実装コードにデバッグ用のログ出力をわざわざ追加して動作確認することも往々にしてありましたので、有用ではありました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.90%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る