5

nullの処理に関連するこの投稿を行っていました。

推奨事項の 1 つ (SO 投稿による) は、null が無効な場合に Assert を使用することです。

私は (これまで) テスト プロジェクトで広範囲にヌルを使用してきました。通常のコード (テスト プロジェクト以外) で Asserts ステートメントを使用するのは奇妙に思えます。

なぜ-> 私はこのように使ったことがないので、それについての本も読んだことがありません.

質問
1. 前提条件に Assert を使用してもよいですか
2. パラメータのチェックと Argument___Exception のスローに対する Assert の長所/短所

問題がある場合は、.NET を求めています (Java ではありません)。

4

4 に答える 4

8

コードコントラクトを調べることをお勧めします。これらはメソッドの静的チェックと実行時チェックの両方を提供し、それらをインターフェースにも適用できるため、コントラクトはパブリックAPIの一部になります。

例として、私自身のコードのいくつかからコピーされたものから(このコードはインターフェース上にコントラクトを実装します):

using System;
using System.Diagnostics.Contracts;

using Project.Contracts.Model.Accounts;
using Project.Contracts.Services;

/// <summary>
/// Data access for accounts.
/// </summary>
[ContractClass(typeof(AccountRepositoryContract))]
public interface IAccountRepository
{
    /// <summary>
    /// Gets the user by id.
    /// </summary>
    /// <param name="userId">The user id.</param>
    /// <returns>The user, or <c>null</c> if user not found.</returns>
    [Pure]
    User GetUserById(int userId);
}

/// <summary>
/// Contract class for <see cref="IAccountRepository"/>.
/// </summary>
[ContractClassFor(typeof(IAccountRepository))]
internal abstract class AccountRepositoryContract : IAccountRepository
{
    /// <summary>
    /// Gets the user by id.
    /// </summary>
    /// <param name="userId">The user id.</param>
    /// <returns>
    /// The user, or <c>null</c> if user not found.
    /// </returns>
    public User GetUserById(int userId)
    {
        Contract.Requires<ArgumentException>(userId > 0);

        return null;
    }
}

より単純でありながらより包括的な例:

public class Foo
{
    public String GetStuff(IThing thing)
    {
        // Throws ArgumentNullException if thing == null
        Contract.Requires<ArgumentNullException>(thing != null);

        // Static checking that this method never returns null
        Contract.Ensures(Contract.Result<String>() != null);

        return thing.ToString();
    }
}
于 2012-12-19T16:52:53.447 に答える
2

この投稿はについてMicrosoft.VisualStudio.TestTools.UnitTesting.Assertあり、 ではありませんDebug.Assert

AssertクラスMicrosoft.VisualStudio.TestTools.UnitTesting名前空間にあり、本番ツールではなくテストを行っているため、お勧めしません。それらも別のアセンブリにあり、テスト以外のコードから参照する必要はありません。

ArgumentExceptionArgumentNullException(さらに分割するためのとを含む不正な引数ArgumentOutOfRangeException) とInvalidOperationException(不正な状態) は、条件チェックのためにあります。

別の方法として、コード コントラクトもあります。スティーブの答えを参照してください。

于 2012-12-19T16:51:29.950 に答える
2

これらは実質的に 2 つの異なる Assert です。単体テストで使用する Assert は、テストの失敗をトリガーするためのものです (もちろん、それらは常にテストされます)。他のコードで使用する Assert は別の関数 ( System.Diagnostics.Debug.Assert()) であり、開発中に補助ツールとして使用され、予想される条件が満たされない場合に警告します。ただし、これらのアサーションはデバッグ ビルドでのみテストされます。リリース ビルドを作成すると、アサートは無効になります。したがって、これは一般的なエラー処理ツールではなく、エラーをキャッチすることを計画するべきではありません。

テストと開発中に論理エラーを見つけて、仮定が成り立つかどうかを知らせるだけです。そのため、はい、事前および事後条件のテストに非常に役立ちます。

この種の Assert は、適切なエラー処理の代わりに最終的に使用する松葉杖になる可能性があるため、少し議論の余地があることに注意してください。また、リリース ビルドでは効果がないため、存在しないエラー処理でソフトウェアをリリースすることになる可能性があります。(例えばAssertでファイルの存在を確認するのはやめましょう。現実世界で実際に起こり得るエラーなので、現実世界でのエラーハンドリングが必要です。)でも個人的には非常に便利なツールだと思いますので、パフォーマンスのオーバーヘッドを気にせずに事前条件と事後条件をテストするため (テストはリリース ビルドで削除されるため、実質的に無料であり、例外をスローするだけでなく、アサーションが失敗したときにデバッガーをトリガーします)

于 2012-12-19T16:55:31.350 に答える
0

個人的には、メソッドで null を処理する場合、そのメソッド内では絶対に使用しませんassert。代わりに、あなたが言うように例外をスローします。

基本的に、アサートが失敗すると、基本的に例外になります。をスローした場合ArgumentNullException、メソッド自体で try catch を使用して何かを行うことは控えますが、単体テスト内でそれを処理します。

public class A
{
  public double Add(double a, double b)
  {
    if (a == null || b == null)
      throw new ArgumentNullException("");
    return a + b;
  }
}

[TestClass()]
public UnitTest
{
  [TestMethod()]
  public void ATest()
  {
    try
    {
      double d = new A().Add(null, 1);
    }
    catch(ArgumentNullException ex)
    {
      //Fail the test
      Assert.Fail("");
      //Or throw, this will allow you to double click the exception in the unit test and go to the line of code which failed
      throw ex;
    }  
  }
}
于 2012-12-19T16:58:34.920 に答える