2016-08-15 10 views
6

私がユニットテストを実装していた頃、私はデータ依存層としてデータベースを持つことが多いため、データアクセス層の単位テストを設定するのに苦労しました。理想的な世界では、ストアドプロシージャコールをモックして外部依存関係を削除します。c#unit testing、mocking stored procedure

しかし、私はMOQ模擬フレームワークでこれを行う方法、またはこれをサポートする他のフレームワークを見つける方法を考え出すことができませんでした。代わりに、私は(私はいつも私が期待している出力を得ることができるように)既知のデータを含むスクリプト化されたテストデータベースを作成することに戻りましたが、これはその層をMockingすることとは少し異なります。

誰でもデータアクセスレイヤのこの部分を模擬する方法を提案できますか?[https://effort.codeplex.com/が存在するEntity Frameworkについて知っていますか?例えば


詳細 私は次のような方法

public object RunStoredProc() 
{ 
    //Some Setup 

    using (SqlConnection conn = new SqlConnection(CONNNECTION_STRING)) 
    { 
     using (SqlCommand comm = new SqlCommand("storedProcName", conn)) 
     { 
      conn.Open(); 
      comm.CommandType = CommandType.StoredProcedure; 
      using (SqlDataReader reader = comm.ExecuteReader()) 
      { 
       while (reader.Read()) 
       { 
        //Logic 
       } 
      } 
     } 
    } 

    //Return object based on logic 
} 

を持っている場合SQLDataReaderは、指定されたデータが含まれるように、そしてどのように私は、ストアドプロシージャの出力を模擬します。より高いレベルでは、RunStoredProc()メソッドをモックすることができますが、それはそのメソッドのロジックが正しいかどうかをテストするのに役立ちません。 「GetDataの」メソッドはprivateである必要がありますよう代わりに私は別の方法

public object RunStoredProc() 
{ 
    //Some Setup 

    List<object> data = GetData(); 
    //Logic 

    //Return object based on logic 
} 

private List<object> GetData() 
{ 
    using (SqlConnection conn = new SqlConnection(CONNNECTION_STRING)) 
    { 
     using (SqlCommand comm = new SqlCommand("storedProcName", conn)) 
     { 
      conn.Open(); 
      comm.CommandType = CommandType.StoredProcedure; 
      using (SqlDataReader reader = comm.ExecuteReader()) 
      { 
       while (reader.Read()) 
       { 
        //place into return object 
       } 
      } 
     } 
    } 
} 

しかしに出SQLReaderを取り除くことができ(公開インタフェースの一部ではない)私は、そのので、問題の遺跡を模擬することはできません。

答えて

3

私たちはすべてのインターフェイス(IDbConnectionIDbTransactionIDbCommandIDataReader)を持っており、彼らは嘲笑と依存性注入を使用することができるように必要な抽象すべてにEF(IDbConnectionFactory)からアイデアを借り思います。私はSqlConnectionと思っています。残りの部分は実装の詳細であり、抽象化することができます。あなたが接続ファクトリ

public interface IDbConnectionFactory { 
    /// <summary> 
    /// Creates a connection based on the given database name or connection string. 
    IDbConnection CreateConnection(string nameOrConnectionString); 
} 

を作成することができますし、それからだけの抽象化を使用するように例示的な方法をリファクタリングすることができますエンティティフレームワークからアイデア後

public class MyDataAccessClass { 
    private IDbConnectionFactory dbConnectionFactory; 
    private string CONNNECTION_STRING = "Connection string here"; 

    public MyDataAccessClass(IDbConnectionFactory dbConnectionFactory) { 
     this.dbConnectionFactory = dbConnectionFactory; 
    } 

    public object RunStoredProc() { 
     //Some Setup 
     List<object> result = new List<object>(); 

     using (IDbConnection conn = dbConnectionFactory.CreateConnection(CONNNECTION_STRING)) { 
      using (IDbCommand comm = conn.CreateCommand()) { 
       comm.CommandText = "storedProcName"; 
       conn.Open(); 
       comm.CommandType = CommandType.StoredProcedure; 
       using (IDataReader reader = comm.ExecuteReader()) { 
        while (reader.Read()) { 
         //...Logic to populate result 
        } 
       } 
      } 
     } 

     //Return object based on logic 
     return result; 
    } 
} 

そこから、選択したモックフレームワークを使用してインターフェイスをモックするか、独自の偽物を作成してメソッドを注入してテストします。

[TestClass] 
public class StoredProcedureUnitTest { 
    [TestMethod] 
    public void TestRunStoredProc() { 
     //Arrange 
     var connectionFactory = new Mock<IDbConnectionFactory>(); 
     //..Setup... 

     var sut = new MyDataAccessClass(connectionFactory.Object); 

     //Act 
     var actual = sut.RunStoredProc(); 

     //Assert 
     //... 
    } 
} 
+0

それがうまくいくようおかげで、)私はこれを正しく読んでいる場合、私はモックする必要があるだろう唯一の方法はIDbCommand.ExecuteReader(だろう、見えます[私はまたにIDbConnection.CreatCommandを模擬する必要があるだろう嘲笑されたIDbCommandを返すが、それは些細なものでなければならない]。他の誰かが他のアイデアを持っている場合は、しばらく質問を残しておきます。 –