1. ホーム
  2. .net

[解決済み] モッキングや単体テストでSqlExceptionを投げるには?

2023-03-05 18:02:06

質問

私はプロジェクトでいくつかの例外をテストしようとしており、私がキャッチした例外の一つは SQlException .

には行けないようです。 new SqlException() に行くことができないようなので、特にデータベースを呼び出すことなく例外を投げることができる方法がわかりません(そして、これらはユニットテストなので、通常、遅いのでデータベースを呼び出さないことをお勧めします)。

私はNUnitとMoqを使用していますが、これを偽造する方法がわかりません。

すべてがADO.NETに基づいているように見えるいくつかの答えに応答して、私はLinq to Sqlを使用していることに注意してください。そのため、そのようなものは舞台裏にあるようなものです。

MattHamilton によって要求されたより多くの情報。

System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class.       
  at Moq.Mock`1.CheckParameters()
  at Moq.Mock`1..ctor(MockBehavior behavior, Object[] args)
  at Moq.Mock`1..ctor(MockBehavior behavior)
  at Moq.Mock`1..ctor()

モックアップを作ろうとしたときに1行目に投稿する

 var ex = new Mock<System.Data.SqlClient.SqlException>();
 ex.SetupGet(e => e.Message).Returns("Exception message");

どのように解決するのですか?

Linq to Sql を使用しているので、NUnit と Moq を使用して、あなたが言及したシナリオをテストするサンプルです。 あなたの DataContext の正確な詳細と、その中で利用可能なものを私は知りません。 あなたのニーズに応じて編集してください。

DataContextをカスタムクラスでラップする必要があります。MoqでDataContextをモックすることはできません。 SqlExceptionもシールされているため、モックできません。 あなた自身のExceptionクラスでラップする必要があります。 この2つを実現するのはそれほど難しいことではありません。

まず、テストを作成しましょう。

[Test]
public void FindBy_When_something_goes_wrong_Should_handle_the_CustomSqlException()
{
    var mockDataContextWrapper = new Mock<IDataContextWrapper>();
    mockDataContextWrapper.Setup(x => x.Table<User>()).Throws<CustomSqlException>();

    IUserResository userRespoistory = new UserRepository(mockDataContextWrapper.Object);
    // Now, because we have mocked everything and we are using dependency injection.
    // When FindBy is called, instead of getting a user, we will get a CustomSqlException
    // Now, inside of FindBy, wrap the call to the DataContextWrapper inside a try catch
    // and handle the exception, then test that you handled it, like mocking a logger, then passing it into the repository and verifying that logMessage was called
    User user = userRepository.FindBy(1);
}

テストを実装してみましょう。まず、Linq to Sqlの呼び出しをリポジトリパターンを使ってラップしてみましょう。

public interface IUserRepository
{
    User FindBy(int id);
}

public class UserRepository : IUserRepository
{
    public IDataContextWrapper DataContextWrapper { get; protected set; }

    public UserRepository(IDataContextWrapper dataContextWrapper)
    {
        DataContextWrapper = dataContextWrapper;
    }

    public User FindBy(int id)
    {
        return DataContextWrapper.Table<User>().SingleOrDefault(u => u.UserID == id);
    }
}

次にIDataContextWrapperをこのように作成すると、このように表示されます。 ブログ記事 をご覧ください。私のは少し違います。

public interface IDataContextWrapper : IDisposable
{
    Table<T> Table<T>() where T : class;
}

次に、CustomSqlException クラスを作成します。

public class CustomSqlException : Exception
{
 public CustomSqlException()
 {
 }

 public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
 {
 }
}

IDataContextWrapperの実装例です。

public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
{
 private readonly T _db;

 public DataContextWrapper()
 {
        var t = typeof(T);
     _db = (T)Activator.CreateInstance(t);
 }

 public DataContextWrapper(string connectionString)
 {
     var t = typeof(T);
     _db = (T)Activator.CreateInstance(t, connectionString);
 }

 public Table<TableName> Table<TableName>() where TableName : class
 {
        try
        {
            return (Table<TableName>) _db.GetTable(typeof (TableName));
        }
        catch (SqlException exception)
        {
            // Wrap the SqlException with our custom one
            throw new CustomSqlException("Ooops...", exception);
        }
 }

 // IDispoable Members
}