java
1assert i == 5 : "i must be 5";
javaの組み込みのassert機能って使い方によっては便利そうな気がするのですが、現場で使われているのを私はほとんど見たことがありません。
これは製品コードに一種のデバックコードが紛れるのが嫌わたり、単体テストが普及して価値を失ったなど何か理由があるのでしょうか?
また、開発現場で実際に使っている(いた)方がいらっしゃれば、使ってよかった・悪かった点などご教授いただけないでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答4件
0
ベストアンサー
アサーションについて、私の考えが既出の意見とは異なるので参戦。
アサーションは、サブルーチンなど、かなり下位の(内部的なモジュールの)インタフェース仕様をコメントのかわりにいれるものと考えています。
コメントで
java
1// 引数Xは必須で null が渡されてくることは考慮していない
と書くかわりに
java
1assert(X!=null)
と書くわけです。コメントと比較して良いところは、結合テスト中にインタフェースミスが
はっきりと分かるところです。 NullPointerException だと、「サブルーチン作成側の考慮漏れによるバグ」なのか「担当者間のインタフェースミス」なのか言い争いになるところを assert を書くことによって「担当者間のインタフェースミス」であることが確定するところにメリットがあります。
一方で assert を書くくらいならそのチェックを正式コードとして入れてはどうかという説もあるかと思います。しかし、内部モジュールのインタフェースミスと Exception という正規の異常系処理ロジックを混在させることは、可読性をさげるとともに、デバッグを難しくします。
java
1public abc(String x, String y) { 2 if (x == null) { 3 throw Excpetion("予想外のエラーが発生しました(関数 abc の第一引数に null が渡されました)"); 4 } 5 if (y == null) { 6 throw Excpetion("予想外のエラーが発生しました(関数 abc の第二引数に null が渡されました)"); 7 }
というようなコーディングを多く見かけるわけですが、これだけだと、この Exception が発生したときにエンドユーザが入力をミスしたのか、システム障害でI/O に失敗したのか、インタフェースミスのバグなのかがコードから判定がつかないわけです。これを assert で書いておけば、インタフェースミスのバグであることが確定でき、可読性を向上させるとともに、トラブルシューティングを簡単にすることが可能です。
投稿2017/09/17 13:10
編集2017/09/17 14:21総合スコア3401
0
JavaだけでなくC/C++やC#にもassertがありますが、確かにあまり使っているのを見たことが無いような気がします。
assertは使い所がかなり限定されたものだと思っています。assertは例外チェックでは無くバグチェック以外にしか使えないからです。
###引数チェック
まず、引数チェックにassertが使えるかです。publicメソッドの引数にassertを使うことは間違っています。もう、初っぱなから全否定です。ただ、privateメソッドに使うことは悪いことではありません。
public class Main { private void puts(String str) { assert str != null; System.out.println(str.toUpperCase()); } public void run() { String str = "Hello, world!"; puts(str); } public static void main(String[] args) { Main main = new Main(); main.run(); } }
puts()
はprivateなので同じクラス内から呼び出せません。そしてnullは渡してはいけないとしましょう(ヌルポになっちゃいますので)。nullを渡さないというのはクラス内の他のメソッド責任です。もし、nullが渡された場合は、バグがあるのはその他のメソッドと言うことになります。
この場合はassertでnullチェックをすることは問題ないと思います。上のコードは単純すぎるのでassertでなくてもわかるかも知れませんが、整数の範囲とか、特定の文字列のみ許しているとか、そういった場合はassertを使った方が何が問題なのかがわかりやすいでしょう。
そして重要なのはUnitTestではどんな引数でそのメソッドを呼び出すのかがチェックできないと言うことです。UintTestは全てのパターンをテストできるわけでは無いため、一部のパターンだけで想定通りの値を必ず渡すとすることはできません。また、テスト失敗時に、何で失敗したのか、何が想定外だったのかも、assertを用いるとわかりやすくなります。
###処理後のチェック
大昔に(訳ありで)書いたJavaのコードからの抜粋を紹介します。(私の本職はJavaプログラマーじゃ無いので、細かいところは大目に見てください。)
Java
1 protected static int[] getLineScore(List<Integer> lineList) { 2 int[] score; 3 score = Com.lineScoreMap.get(lineList); 4 if (score == null) { 5 score = calcLineScore(lineList); 6 // 新たに作成してからMapに配置しないといけない! 7 // 計算結果は常胃同じはず。 8 // 変更しないので同期もいらないはず。 9 Com.lineScoreMap.put(new ArrayList<Integer>(lineList), score); 10 } 11 12 assert score.length == 3 : "スコアのサイズが3じゃない、score.length = " + "depth:" 13 + score.length; 14 15 return score; 16 }
コメントに誤字が混ざってますが、そこはご愛敬で。caleLineScore()
は必ず長さ3のintの配列を返すようになっています。もちろん別途UnitTestは存在しますが、本当に常に長さ3のintの配列を返すかどうかはわかりません。また、キャッシュしているCom.lineScoreMap
に変なものが混ざっている可能性もあります。そもそも同期いらないとか書いているけど、これ本当なのかな…。
ぶっちゃけ、怪しすぎるので戻ってきた値や前の処理をassertでチェックしています。もし、おかしい値が返ってきていたら、その後の処理がうまく動かないからです。
もし、assertがなかったら、その後の処理の深いところでエラーになるかも知れません。そこから、どこで間違っていたかを辿ることはかなり大変です。ですが、ここでassert失敗になれば、その前のcaleLineScore()
あたりがおかしいとあたりを付けられます。バグの原因もすぐに見つけられるでしょう。
###デバッグの時だけエラー
assertは実行時にオプションを付けないと有効になりません。本来、想定とは違う場合は、なんらかのバグが発生しているため、停止してエラーになった方がデバッグがしやすくなります。しかし、本番環境ではある程度の想定外は無視してなるべく安定して動いて欲しいと思います。また昔のコードの抜粋です。
Java
1 public static boolean isFrozenBoardList(List<List<Integer>> boardList) { 2 if (boardList.get(Com.LINES).get(5) == 0) { 3 return false; 4 } else { 5 assert boardList.get(Com.LINES).get(5) == 1 : "固定フラグが未知数です。" 6 + boardList.get(Com.LINES).get(5); 7 return true; 8 } 9 }
boardList.get(Com.LINES).get(5)
は必ず0か1です。バグが無ければですが。ですが、本番環境では、もし、想定外の値だった場合でもそのまま進みたいと考えています。逆にデバッグ時はなるべくすぐにエラーになって止まって欲しいと考えています。二つの動作が行えるようにassertを使っていると言うことです。
私の思いつくのはこれぐらいです。上の抜粋したコードは別途UnitTestも存在し、そちらで単体テストも行っています。しかし、全てのパターンも網羅することは不可能なので、結合テストの時にassertを有効にして、想定外の動作がしていないかをチェックするようにしました。
assertは本番では無効にして使う物だと思っています。単体テストの時に想定外の値になっているかのチェックをわかりやすくする、結合テストの時に単体テストでは網羅できなかったパターンがやってきて、想定外の値になっていないかチェックする。そういったことぐらいにしか使えないと思います。ただ、assertは任意のメッセージを書くことができますので、うまく使えば、デバッグがしやすくなる、バグの原因追求が早くなると思います。
まぁ、私はJavaプログラマーでは無いので、Javaはほとんど書かないから、実際の現場がどうしているのかはちょっとわからないのですけど。
投稿2017/09/17 23:56
総合スコア21751
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
javaの組み込みのassert機能についてですが、assert結果がFasleの場合にプログラムが終了するのはご存知かと思います。
通常のプログラムにおいては、assert結果がFalseの場合、Exceptionを発生させて上で、
エラー処理クラスでExceptionをキャッチし、エラー内容をユーザー画面に返却する処理が実装されます。
なぜならばただシステムエラーが返却されてもユーザーが次に何をしたらいいかわからないからです。
よって、assertではなくif文などでパラメータ(=引数)チェックを実施し、不正な値が入っている場合にExceptionなどを発生させる処理を実装することが一般的と思います。
※複雑な業務アプリケーションになると、業務ロジックの前に全てのパラメータのチェックを実施する処理を用意し、不正な値が入っている場合には業務ロジックに入る前に画面に折り返してしまう場合もあります。そのような場合は業務ロジッククラスは正しい値が入ってくる前提で処理を実装しても良い場合があります。
以上の理由により、javaの組み込みのassert機能は使われないと考えています。
投稿2017/09/17 08:48
総合スコア316
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
以下が参考になるかと。
Javaのアサーションと単体テストについて
ただ、両方しっかり書いているコードにはなかなかお目にかからないというのが個人的な感覚です。
(特にアサーションがないほうが多い印象)
投稿2017/09/17 04:18
総合スコア946
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/17 13:24 編集
2017/09/17 13:40
2017/09/17 13:51
2017/09/17 14:03
2017/09/17 14:22
2017/09/17 17:12
2017/09/18 04:12
2017/09/18 04:18
2017/09/18 04:29