Debug.Assert()はいつ使用する必要がありますか?


220

私は約1年間プロのソフトウェアエンジニアとして、CSの学位を取得しています。私はC ++とCでアサーションについてしばらく知っていましたが、最近までC#と.NETにアサーションが存在することをまったく知りませんでした。

私たちのプロダクションコードにはアサートがまったく含まれておらず、私の質問はこれです...

製品コードでアサートの使用を開始する必要がありますか?もしそうなら、いつその使用が最も適切ですか?行う方が理にかなっていますか

Debug.Assert(val != null);

または

if ( val == null )
    throw new exception();

2
あなたが設定した二分法が手掛かりです。これは、どちらか、または例外とアサートの問題ではなく、両方と防御コードの問題です。何をすべきかは、あなたが理解しようとしていることです。
Casper Leon Nielsen

5
私は、誰かが例外またはその他のクラッシュ方法が「これから賢明に回復する方法がない」という状況には適切であると提案し、さらに「これは決して発生してはならない」という状況にアサートが適切であるという提案を読みました。しかし、前者も満たすことなく後者の条件を満たす現実的な状況は何でしょうか?アサーションがプロダクションでオンのままであるPythonのバックグラウンドから来て、プロダクションで検証の一部をオフにするJava / C#のアプローチを理解したことがありません。私が実際に見ることができる唯一のケースは、検証が高価であるかどうかです。
Mark Amery 2013


2
個人的に私はパブリックメソッドの例外とプライベートメソッドのアサーションを使用しています。
フレッド

回答:


230

デバッグは、Microsoft .NET 2.0アプリケーションジョンロビンスは、アサーションに大きなセクションがあります。彼の主なポイントは次のとおりです。

  1. 寛大に主張する。アサーションが多すぎることはありません。
  2. アサーションは例外を置き換えるものではありません。例外は、コードが要求するものをカバーします。アサーションは、想定していることをカバーします。
  3. よく書かれたアサーションは、何がどこで(例外のように)発生したかだけでなく、その理由も教えてくれます。
  4. 多くの場合、例外メッセージは暗号化されている可能性があり、コードを逆にたどってエラーの原因となったコンテキストを再作成する必要があります。アサーションは、エラーが発生したときのプログラムの状態を保持できます。
  5. アサーションはドキュメントを兼ねており、コードが依存する暗黙の仮定を他の開発者に伝えます。
  6. アサーションが失敗したときに表示されるダイアログを使用すると、デバッガをプロセスにアタッチできるので、ブレークポイントをそこに置いたかのようにスタックをざっと見ることができます。

PS:Code Completeが気に入った場合は、この本でフォローすることをお勧めします。WinDBGとダンプファイルの使い方を学ぶために購入しましたが、前半にはバグを回避するためのヒントが満載されています。


3
簡潔で役立つ要約の+1。非常に直接適用できます。ただし、私にとって欠けている主なものは、Trace.AssertとTrace.Assertのどちらを使用するかです。つまり、プロダクションコードでそれらを行う/望まない場合についての何か。
Jon Coombs 2013

2
JonCoombsは「Trace.Assert対Trace.Assert」のタイプミスですか?
thelem 2015

1
@thelemたぶんジョンはDebug.AssertTrace.Assert。後者は、リリースビルドとデバッグビルドで実行されます。
DavidRR

例外をスローするよりもDebug.Assertを優先する必要があるのはなぜですか?
バリスAkkurt

86

置くDebug.Assert()あなたは不変条件を確保するための健全性チェックを持っていたいコードでどこでも。リリースビルドをコンパイルするとき(つまり、DEBUGコンパイラ定数がない場合)への呼び出しDebug.Assert()は削除されるため、パフォーマンスに影響を与えません。

を呼び出す前に、例外をスローする必要がありDebug.Assert()ます。アサートは、まだ開発中にすべてが期待どおりであることを確認するだけです。


35
呼び出す前に例外をスローするのに、なぜアサーションを入れるのか明確にできますか?それとも私はあなたの答えを誤解しましたか?
Roman Starkov

2
@romkyns含めない場合、リリースモードでプロジェクトをビルドすると、すべての検証/エラーチェックがなくなるため、それらを含める必要があります。
オスカーメデロス

28
@オスカー私はそもそもアサーションを使用することのすべてのポイントだと思った... OK、それであなたはそれらの前に例外を置きました-それからなぜアサーションを後に置くのですか?
Roman Starkov、

4
@superjos:私は反対しなければなりません:MacLeodの回答のポイント#2には、実際にはアサーションと例外が必要ですが、同じ場所には必要がないと述べています。変数にNullRefExをスローし、その直後にAssertを実行しても意味がありません(assertメソッドは、この場合、assertの目的であるダイアログボックスを表示しません)。MacLeodの意味するところは、例外が必要な場所もあれば、Assertで十分な場所もあります。
David

1
誰か他の人の答えの私の解釈を解釈するのは面倒になるかもしれません:)とにかく私はこれらについてあなたと一緒に:あなたはそれらの両方を必要とし、あなたは断言のに例外を置くべきではありません。「同じ場所にない」の意味がわかりません。繰り返しになりますが、解釈を拒否して、考え/好みを述べます。いくつかの操作を開始する前に前提条件を確認するため、または操作後に事後条件を確認するために、1つ以上のアサートを配置します。アサートに加えて、アサーションの後に、何か問題が発生して例外をスローする必要があるかどうかを確認します。
superjos 2012年

52

コード完了から

8防御プログラミング

8.2アサーション

アサーションは、開発中に使用されるコード(通常はルーチンまたはマクロ)であり、プログラムが実行中にプログラム自体をチェックできるようにします。アサーションがtrueの場合、それはすべてが期待どおりに動作していることを意味します。falseの場合は、コードで予期しないエラーが検出されたことを意味します。たとえば、顧客情報ファイルに50,000を超えるレコードが含まれないとシステムが想定している場合、プログラムには、レコードの数が50,000以下であるというアサーションが含まれる場合があります。レコード数が50,000以下である限り、アサーションはサイレントになります。ただし、50,000件を超えるレコードが検出された場合は、プログラムにエラーがあることを大声で「アサート」します。

アサーションは、大きくて複雑なプログラムや信頼性の高いプログラムで特に役立ちます。これにより、プログラマは、一致しないインターフェイスの仮定、コードが変更されたときに侵入するエラーなどをより迅速に洗い出すことができます。

通常、アサーションは2つの引数を取ります。1つは真であると想定される仮定を説明するブール式で、もう1つはそうでない場合に表示するメッセージです。

(…)

通常、プロダクションコードでアサーションメッセージをユーザーに表示しないようにします。アサーションは、主に開発および保守中に使用するためのものです。アサーションは通常、開発時にコードにコンパイルされ、本番用にコードからコンパイルされます。開発中、アサーションは矛盾する仮定、予期しない条件、ルーチンに渡された不正な値などを洗い流します。本番環境では、アサーションによってシステムのパフォーマンスが低下しないように、コードからコンパイルされます。


7
では、本番環境で見つかった顧客情報ファイルに50,000を超えるレコードが含まれている場合はどうなるでしょうか。アサーションがプロダクションコードからコンパイルされ、この状況が別の方法で処理されない場合、これは問題を引き起こしませんか?
DavidRR

1
@DavidRRはい、確かに。しかし、プロダクションが問題を通知し、一部の開発者(このコードをよく知らない可能性があります)が問題をデバッグするとすぐに、アサーションは失敗し、開発者はシステムが意図したとおりに使用されていないことをすぐに認識します。
Marc

48

FWIW ...私のパブリックメソッドはif () { throw; }、メソッドが正しく呼び出されるようにするためにパターンを使用する傾向があることがわかりました。私の私的な方法はよく使う傾向がありますDebug.Assert()

私のプライベートメソッドでは、自分が制御下にあるので、パラメーターが正しくない独自のプライベートメソッドの1つを呼び出し始めると、どこかで自分の仮定が破られてしまいます-決して得ていないはずですその状態に。本番環境では、これらのプライベートアサートは、内部状態を有効で一貫性のある状態に保つことになっているため、不必要な作業であることが理想的です。実行時に誰でも呼び出すことができるパブリックメソッドに与えられたパラメーターとは対照的です。例外をスローすることによって、パラメーターの制約を強制する必要があります。

さらに、実行時に何かが機能しない場合(ネットワークエラー、データアクセスエラー、サードパーティのサービスから取得した不正なデータなど)、プライベートメソッドは例外をスローする可能性があります。私のアサートは、オブジェクトの状態に関する自分の内部仮定を壊していないことを確認するためだけにあります。


3
これは優れた実践の非常に明確な説明であり、尋ねられた質問に対して非常に合理的な答えを提供します。
キャスパーレオンニールセン

42

アサーションを使用して開発者の想定を確認し、例外を使用して環境の想定を確認します。


31

もし私があなただったら、そうします:

Debug.Assert(val != null);
if ( val == null )
    throw new exception();

または、状態チェックの繰り返しを回避する

if ( val == null )
{
    Debug.Assert(false,"breakpoint if val== null");
    throw new exception();
}

5
これはどのように問題を解決していますか?これにより、debug.assertは無意味になります。
平凡な2008

43
いいえ、そうではありません。例外がスローされる直前の時点でコードに侵入します。コードのどこかでtry / catchを行っている場合、例外に気付かないこともあります。
マークイングラム

2
+1私は多くの問題を抱えていて、人々は何もせずに単に例外を試行/キャッチするだけなので、バグの追跡が問題でした
dance2die

5
これを実行したい場合があると思いますが、一般的な例外をキャッチするべきではありません!
Casebash、2009年

8
@MarkIngram回答に-1、コメントを正当化する+1。これは特定の特殊な状況では便利なトリックですが、すべての検証で一般的に行うのは奇妙なことのようです。
Mark Amery 2013

24

プロダクションコード(リリースビルドなど)でアサートが必要な場合は、Debug.Assertの代わりにTrace.Assertを使用できます。

もちろん、これは本番実行可能ファイルにオーバーヘッドを追加します。

また、アプリケーションがユーザーインターフェイスモードで実行されている場合は、デフォルトで[アサーション]ダイアログが表示されますが、これはユーザーにとって少し戸惑うかもしれません。

DefaultTraceListenerを削除することで、この動作をオーバーライドできます。MSDNのTrace.Listenersのドキュメントを参照してください。

要約すれば、

  • Debug.Assertを自由に使用して、Debugビルドのバグをキャッチします。

  • ユーザーインターフェイスモードでTrace.Assertを使用する場合は、ユーザーを混乱させないように、DefaultTraceListenerを削除することをお勧めします。

  • テストする条件がアプリで処理できないものである場合は、実行が継続しないように、例外をスローすることをお勧めします。ユーザーはアサーションを無視することを選択できることに注意してください。


1
OPが本番用コードについて具体的に尋ねたため、Debug.AssertとTrace.Assertの重要な違いを指摘するための+1。
Jon Coombs 2013

21

アサートは、ユーザーエラーではなく、プログラマー(ユーザー)エラーをキャッチするために使用されます。これらは、ユーザーがアサートを起動できる可能性がない場合にのみ使用してください。たとえば、APIを作成している場合、APIユーザーが呼び出すことができるメソッドで引数がnullでないことを確認するためにアサートを使用しないでください。ただし、APIの一部として公開されていないプライベートメソッドで使用して、想定されていないコードがnull引数を渡さないことをアサートできます。

私は通常、わからない場合はアサートよりも例外を優先します。


11

要するに

Asserts ガードおよび契約による設計のチェックに使用されます。

  • Assertsデバッグビルドと非プロダクションビルド専用です。アサートは通常、リリースビルドではコンパイラによって無視されます。
  • Asserts システムの制御下にあるバグ/予期しない状態をチェックできます
  • Asserts ユーザー入力またはビジネスルールの最初の行の検証のためのメカニズムではありません
  • Asserts予期しない環境条件(コードの制御外)を検出するために使用しないでください。たとえば、メモリ不足、ネットワーク障害、データベース障害などです。まれではありますが、これらの状態は予期されるものです(そして、アプリコードは次のような問題を修正できません)ハードウェア障害またはリソース枯渇)。通常、例外がスローされます。アプリケーションは、修正アクション(データベースまたはネットワーク操作の再試行、キャッシュメモリの解放の試行など)を実行するか、例外を処理できない場合は正常に中止できます。
  • 失敗したアサーションはシステムにとって致命的であるはずです。つまり、例外とは異なり、失敗を試みたり、処理したりしないでくださいAsserts。コードは予期しない領域で動作しています。スタックトレースとクラッシュダンプを使用して、問題の原因を特定できます。

アサーションには大きなメリットがあります。

  • ユーザー入力の検証の欠落、または上位レベルのコードの上流のバグを見つけるのを支援するため。
  • コードベースのアサートは、コードで行われた仮定を読者に明確に伝えます
  • アサートはDebugビルドの実行時にチェックされます。
  • コードを徹底的にテストしたら、リリースとしてコードを再構築すると、仮定を検証するためのパフォーマンスオーバーヘッドがなくなります(ただし、必要に応じて、後のデバッグビルドが常にチェックを元に戻すという利点があります)。

... もっと詳しく

Debug.Assertプログラムの制御内の残りのコードブロックによって状態について想定されている条件を表します。これには、提供されたパラメーターの状態、クラスインスタンスのメンバーの状態、またはメソッド呼び出しからの戻りがその縮小された/設計された範囲内にあることが含まれます。通常、アサートは必要なすべての情報(スタックトレース、クラッシュダンプなど)を使用してスレッド/プロセス/プログラムをクラッシュさせる必要があります。これらは、設計されていないバグまたは想定外の状態の存在を示すためです(つまり、試行してキャッチしないか、アサーション障害の処理)、アサーション自体がバグよりも大きな損傷を引き起こす可能性がある場合を除いて1つの例外があります(たとえば、航空機が潜水艦に入るときに航空管制官はYSODを望まないが、デバッグビルドを展開する必要があるかどうかは疑わしい生産...)

いつ使用するべきかAsserts? -システム、ライブラリAPI、またはサービスの任意の時点で、関数またはクラスの状態への入力が有効であると想定される場合(たとえば、システムのプレゼンテーション層のユーザー入力で検証がすでに行われている場合) 、ビジネス層とデータ層のクラスは、通常、入力のnullチェック、範囲チェック、文字列長チェックなどがすでに行われていることを前提としています)。-一般的なAssertチェックには、無効な仮定がnullオブジェクト逆参照、ゼロ除数、数値または日付の算術オーバーフロー、および一般的な帯域外/動作用に設計されていない場合(たとえば、32ビットintが人間の年齢をモデル化するために使用された場合)が含まれます、Assert年齢が実際に0から125の間であることが賢明です。-100と10 ^ 10の値は設計されていません)。

.Netコードコントラクト
.Netスタックでは、コードコントラクトに加えて、またはの代わりに使用できDebug.Assertます。コードコントラクトは、状態チェックをさらに形式化し、コンパイル時(またはIDEでバックグラウンドチェックとして実行した場合は、その後すぐに)の違反の検出を支援できます。

利用可能なDesign by Contract(DBC)チェックには、次のものがあります。

  • Contract.Requires -契約済み前提条件
  • Contract.Ensures -契約後の条件
  • Invariant -寿命のすべてのポイントにおけるオブジェクトの状態に関する仮定を表します。
  • Contract.Assumes -非コントラクト装飾メソッドへの呼び出しが行われたときに静的チェッカーを一時停止します。

残念ながら、MSがコード契約の開発を中止したため、コード契約はほとんど死んでいます。
マイクローリー

10

私の本ではほとんどありません。ほとんどの場合、すべてが正常かどうかを確認したい場合は、正常でない場合はスローします。

嫌いなのは、デバッグビルドとリリースビルドの機能が異なることです。デバッグアサートが失敗しても機能がリリースで機能する場合、それはどのように意味がありますか?アサーターが長い間会社を辞めていて、誰もコードのその部分を知らない場合はさらに良いでしょう。次に、問題を調査して、それが本当に問題であるかどうかを確認するために、時間をいくらか殺す必要があります。それが問題だとしたら、そもそもなぜ人は投げないのでしょうか?

これは、Debug.Assertsを使用して問題を他の人に任せることを提案し、自分で問題に対処します。何かがそうであるはずであり、それがスローされない場合は、スローします。

アサーションを最適化したいパフォーマンスクリティカルなシナリオがあり、それらが役立つ場合があると思いますが、まだそのようなシナリオに遭遇することはありません。


4
あなたが答えるのは、いくつかのメリットに値しますが、それらに関して頻繁に懸念が高まっていること、デバッグセッションが中断されていること、および誤検知の可能性があることを強調しています。ただし、いくつかの微妙な部分が欠けており、「最適化アサート」を記述しています。これは、例外のスローとdebug.assertの実行は同じであるという考えにのみ基づいています。そうではありません。賛成投票のいくつかでわかるように、それらは異なる目的と特性を提供します。DW
キャスパーレオンニールセン

以下のための+1 「デバッグアサートに失敗した場合、私は嫌い何が。それはリリースビルドと機能的に異なるデバッグビルドを行っているという事実であるが、機能をリリースして動作し、その後どのようにそれがどんな意味を成していますか?」.NETではSystem.Diagnostics.Trace.Assert()、リリースビルドとデバッグビルドで実行されます。
DavidRR

7

よるとIDesign標準、あなたがすべき

すべての仮定を表明します。平均して、5行ごとがアサーションです。

using System.Diagnostics;

object GetObject()
{...}

object someObject = GetObject();
Debug.Assert(someObject != null);

免責事項として、このIRLを実装することは実用的ではないことを述べておきます。しかし、これは彼らの標準です。


Juval Lowyは自分を引用するのが好きなようです。
devlord

6

アサーションは、リリースビルドのチェックを削除する場合にのみ使用してください。デバッグモードでコンパイルしないと、アサーションは起動しません。

nullの確認の例を考えると、これが内部専用のAPIの場合、アサーションを使用できます。公開APIの場合は、明示的なチェックとスローを必ず使用します。


.NETではSystem.Diagnostics.Trace.Assert()、リリース(製品)ビルドでアサーションを実行するために使用できます。
DavidRR

コード分​​析ルールCA1062:パブリックメソッドの引数を検証するには 、次の場合に引数をチェックする必要がありますこのような状況では、メソッドまたはプロパティがスローする必要があります。null ArgumentNullException
DavidRR 2016

6

すべてのアサートは、次のように最適化できるコードである必要があります。

Debug.Assert(true);

それはあなたがすでに真実であると想定している何かをチェックしているからです。例えば:

public static void ConsumeEnumeration<T>(this IEnumerable<T> source)
{
  if(source != null)
    using(var en = source.GetEnumerator())
      RunThroughEnumerator(en);
}
public static T GetFirstAndConsume<T>(this IEnumerable<T> source)
{
  if(source == null)
    throw new ArgumentNullException("source");
  using(var en = source.GetEnumerator())
  {
    if(!en.MoveNext())
      throw new InvalidOperationException("Empty sequence");
    T ret = en.Current;
    RunThroughEnumerator(en);
    return ret;
  }
}
private static void RunThroughEnumerator<T>(IEnumerator<T> en)
{
  Debug.Assert(en != null);
  while(en.MoveNext());
}

上記では、nullパラメータには3つの異なるアプローチがあります。1つ目は、それを許容できるものとして受け入れます(何もしません)。2番目は、呼び出しコードが処理するための例外をスローします(または処理せず、エラーメッセージが表示されます)。3番目は、それが起こり得ないと想定し、そうであると断言します。

前者の場合は問題ありません。

2番目のケースでは、呼び出しコードに問題があります-nullで呼び出すべきではなかったGetFirstAndConsumeため、例外が返されます。

3番目のケースでは、このコードに問題があります。en != nullこれは、呼び出される前にすでにチェックされているはずなので、それが真実ではないことがバグであるためです。または、言い換えると、理論的にに最適化できるコードである必要がありDebug.Assert(true)、sicne en != nullは常にtrue


1
それでは、3番目のケースでen == nullは、本番環境ではどうなりますか?(プログラムが完全にデバッグされているため)本番環境でen == null決して起こり得ないと言っているでしょうか?もしそうなら、Debug.Assert(en != null)少なくともコメントの代わりとして機能します。もちろん、将来の変更が行われた場合でも、起こり得る回帰を検出するための価値はあります。
DavidRR

@DavidRR、私は確かにそれが決してnullになり得ないことを主張しており、それがコードの表明であり、したがって名前です。もちろん、私は間違っていたり、変更によって間違っていたりする可能性があり、それがassert呼び出しの値です。
Jon Hanna

1
への呼び出しDebug.Assert()はリリースビルドで削除されます。あなたがあれば、ある間違った、第三の場合には、あなたは(生産のリリースビルドの使用を想定)の生産でそれを知ることができません。ただし、1番目と2番目のケースの動作は、デバッグビルドとリリースビルドで同じです。
DavidRR

@DavidRR。これは、状態のチェックではなく、事実の表明であるため、発生しないと私が判断した場合にのみ適切になります。もちろん、アサーションがあり、キャッチするバグがあっても、テストでそのケースにヒットすることはありません。
Jon Hanna

4

Debug.Assertが正しい選択になる4つのケースを追加すると思いました。

1)ここで言及していないのは、自動テスト中にアサートが提供できる追加の概念的範囲です。簡単な例として:

追加のシナリオを処理するためにコードのスコープを拡張したと信じている作者によって、より高いレベルの呼び出し元が変更された場合、理想的には(!)この新しい条件をカバーするユニットテストを記述します。完全に統合されたコードが正常に機能しているように見える場合があります。

ただし、実際には微妙な欠陥が導入されていますが、テスト結果では検出されていません。呼び出し先は、この場合には非決定的となり、そして唯一たたまたま期待される結果を提供します。または、気づかれない丸め誤差が発生した可能性があります。または、他の場所で同様に相殺されたエラーを引き起こした。または、要求されたアクセスだけでなく、付与すべきでない追加の特権も付与されます。等。

この時点で、ユニットテストによって駆動された新しいケース(またはエッジケース)と結合された呼び出し先に含まれるDebug.Assert()ステートメントは、元の作成者の仮定が無効にされているため、テスト中に貴重な通知を提供できます。追加のレビューなしでリリースされます。単体テスト付きのアサートは完璧なパートナーです。

2)さらに、いくつかのテストは簡単に作成できますが、初期の想定を考えると高コストで不要です。例えば:

セキュリティで保護された特定のエントリポイントからのみオブジェクトにアクセスできる場合、すべてのオブジェクトメソッドからネットワーク権利データベースに対して追加のクエリを実行して、呼び出し元にアクセス許可があることを確認する必要がありますか?きっとそうではない。おそらく、理想的なソリューションには、キャッシングやその他の機能の拡張が含まれますが、設計では必要ありません。Debug.Assert()は、オブジェクトが安全でないエントリポイントにアタッチされるとすぐに表示されます。

3)次に、一部のケースでは、リリースモードで展開したときに、製品の操作のすべてまたは一部に対して有用な診断相互作用がない場合があります。例えば:

組み込みのリアルタイムデバイスであるとします。例外をスローし、不正な形式のパケットに遭遇したときに再起動することは、逆効果です。代わりに、デバイスは、出力にノイズをレンダリングする点まで、ベストエフォート型の操作から恩恵を受ける可能性があります。また、ヒューマンインターフェイスやログデバイスがない場合や、リリースモードで展開したときに人間が物理的にアクセスできない場合もあり、同じ出力を評価することでエラーを認識できます。この場合、リベラルなアサーションと徹底的なプレリリーステストは、例外よりも価値があります。

4)最後に、呼び出し先が非常に信頼できると見なされているという理由だけで一部のテストは不要です。ほとんどの場合、再利用可能なコードが多いほど、コードを信頼できるものにするために多くの努力が払われています。したがって、呼び出し元からの予期しないパラメーターの場合は例外が一般的ですが、呼び出し先からの予期しない結果の場合はアサートします。例えば:

コアString.Findオペレーションで-1、検索条件が見つからないときにaが返されると記載されている場合、3つではなく1つのオペレーションを安全に実行できる可能性があります。ただし、実際に返された-2場合は、合理的な対応策がない可能性があります。単純な計算を-1値を個別にテストする計算に置き換えることは役に立たず、コアライブラリが期待どおりに動作していることを確認するテストでコードを散らかすために、ほとんどのリリース環境では不合理です。この場合、アサートが理想的です。


4

実用的なプログラマーから引用:ジャーニーマンからマスターへ

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

アサーションに関してよくある誤解があり、コンパイラや言語環境を書く人々によって公布されています。それはこのようなものになります:

アサーションはコードにオーバーヘッドを追加します。彼らは決して起こってはならないことをチェックするので、コードのバグによってのみトリガーされます。コードがテストされて出荷されると、それらは不要になり、コードをより高速に実行するためにオフにする必要があります。アサーションはデバッグ機能です。

ここには2つの明らかに間違った仮定があります。まず、テストではすべてのバグが検出されると想定しています。実際には、複雑なプログラムの場合、コードが通過する順列のごく一部をテストすることはほとんどありません(無慈悲なテストを参照)。

第二に、楽観主義者は、プログラムが危険な世界で実行されることを忘れています。テスト中、ラットはおそらく通信ケーブルをかじることはなく、ゲームをプレイしている誰かがメモリを使い果たすことはなく、ログファイルがハードドライブをいっぱいにすることもありません。これらのことは、プログラムが実稼働環境で実行されるときに発生する可能性があります。最初の防御策は、起こり得るエラーをチェックすることであり、2番目の防御策は、アサーションを使用して、見逃したエラーを検出することです。

プログラムを本番環境に配信するときにアサーションをオフにすることは、実際には一度行ったので、ネットなしでハイワイヤを通過するようなものです。劇的な価値がありますが、生命保険を取得することは困難です。

パフォーマンスに問題がある場合でも、実際に影響を与えるアサーションのみをオフにしてください


2

常に2番目のアプローチ(例外をスローする)を使用する必要があります。

また、本番環境にいる場合(およびリリースビルドがある場合)は、無効な値を操作するよりも例外をスローして(そして最悪の場合はアプリをクラッシュさせて)、顧客のデータを破壊することをお勧めします(これには数千もかかる可能性があります)ドル)。


1
いや、他のいくつかの答えと同じです:あなたは違いを本当に理解していないので、提供の1つをオプトアウトし、その過程でそれらの間に誤った二分法を設定します。DW
キャスパーレオンニールセン

3
これは、このリストIMOの唯一の正しい答えです。簡単にキャスパーを却下しないでください。デバッグアサートはアンチパターンです。デバッグ時に不変の場合、実行時に不変。アプリが壊れた不変条件で続行できるようにすると、確定的でない状態になり、クラッシュよりも問題が悪化する可能性があります。IMO両方のビルドで同じコードを使用し、コントラクトが壊れるとすぐに失敗し、トップレベルで堅牢なエラー処理を実装することをお勧めします。たとえば、コンポーネントを分離し、コンポーネントを再起動する機能を実装します(ブラウザでタブがクラッシュしてもブラウザ全体はクラッシュしない)。
justin.m.chase 2013

1
同じ議論では無視できないため、ここでの議論にTrace.Assertを含めると役立つ場合があります。
Jon Coombs

0

プログラムの論理エラーをテストするには、Debug.Assertを使用する必要があります。コンパイラは構文エラーについてのみ通知できます。したがって、論理エラーをテストするには、Assertステートメントを明確に使用する必要があります。たとえば、青のBMWだけが15%割引になる自動車を販売するプログラムをテストするとします。コンパイラーは、プログラムがこれを実行する上で論理的に正しいかどうかについては何も通知しませんが、assertステートメントはそうすることができます。


2
申し訳ありませんが例外はすべて同じことを行うので、この回答は本当の質問には対応していません。
Roman Starkov、2009年

0

ここで答えを読んだので、重要な違いを付け加えるべきだと思いました。アサートが使用される方法は2つあります。1つは、プログラムが続行できる場合に、条件付きブレークポイントのような「これは実際には発生しないので、通知されて何をすべきかを決定できる」の一時的な開発者のショートカットとしてです。もう1つは、コードに有効なプログラムの状態に関する仮定を置く方法の1つです。

最初のケースでは、アサーションは最終的なコードにある必要さえありません。Debug.Assert開発中に使用する必要があり、不要になった場合は削除できます。それらを残したい場合、またはそれらを削除することを忘れても問題はありません。これらはリリースのコンパイルに影響を与えないためです。

しかし2番目のケースでは、アサーションはコードの一部です。彼らはまあ、あなたの仮定は真実であると断言し、またそれらを文書化します。その場合は、コードにそのまま残しておきます。プログラムが無効な状態の場合、続行を許可しないでください。パフォーマンスに影響を与える余裕がなければ、C#を使用することはできません。一方で、それが発生した場合にデバッガをアタッチできると便利な場合があります。もう1つは、スタックトレースをユーザーに表示させたくない場合であり、さらに重要なのは、ユーザーがそれを無視できないようにすることです。また、サービス内にある場合は常に無視されます。したがって、本番環境での正しい動作は、例外をスローし、プログラムの通常の例外処理を使用することです。これにより、ユーザーに適切なメッセージが表示され、詳細がログに記録されます。

Trace.Assertこれを達成するための完璧な方法があります。本番環境では削除されず、app.configを使用してさまざまなリスナーで設定できます。そのため、開発ではデフォルトのハンドラーで問題ありません。本番環境では、以下のような簡単なTraceListenerを作成して例外をスローし、本番環境設定ファイルでアクティブ化できます。

using System.Diagnostics;

public class ExceptionTraceListener : DefaultTraceListener
{
    [DebuggerStepThrough]
    public override void Fail(string message, string detailMessage)
    {
        throw new AssertException(message);
    }
}

public class AssertException : Exception
{
    public AssertException(string message) : base(message) { }
}

そして、プロダクション構成ファイルで:

<system.diagnostics>
  <trace>
    <listeners>
      <remove name="Default"/>
      <add name="ExceptionListener" type="Namespace.ExceptionTraceListener,AssemblyName"/>
    </listeners>
  </trace>
 </system.diagnostics>

-1

C#と.NETでどのように機能するかはわかりませんが、Cではassert()は-DDEBUGでコンパイルされた場合にのみ機能します。開発者専用です。私はそれを頻繁に使用していますが、バグを追跡する方が簡単な場合があります。


-1

量産コードでは使用しません。例外をスローし、キャッチしてログに記録します。

asp.netでも注意が必要です。アサートがコンソールに表示され、リクエストがフリーズする可能性があるためです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.