2016-01-22 23 views
6

私は、私たちの製品のいずれかのユニットテストを書いているし、正常にEntity Frameworkのへの接続を模擬するために部品番号を使用されています。MoqとSqlConnection?

public static productValue findValues(string productName, string dbConnectionString) 
{ 
    try 
    { 
     SqlConnection conn = new SqlConnection(dbConnectionString); 
     conn.Open(); 
     //Do stuff 
    } 
} 

渡された接続文字列を使用して、そのメソッド内で当社のデータベースにアクセスします。しかし、私は、以下の方法に遭遇しました。 Moqを使って模擬DBを設定し、模擬DBを指す接続文字列を作成することは可能ですか?私はわからないんですけれども、これは正しいアプローチであれば、これは接続自体ではなく、DBをモックと同じように私は、

var mockSqlConnnection = new Mock<SqlConnection>(); 

の線に沿って何かをしようとしてきました。

+1

SqlConnectionは密閉されたクラスであると信じられないので、嘲笑することはできません。あなたはIDBConnectionをモックすることができますが、さらに多くのことがあります:このメソッドを単体テストしたい場合は、少しリファクタリングする必要があります。 – stuartd

+1

SqlConnectionは密接なクラスです – Novastorm

+1

[ビジネスロジックテストで嘲笑される抽象的なインターフェイスの背後にあるデータアクセスを非表示にするには、データベースを取得する最善の方法の1つは](http:// codebetter .com/jeremymiller/2005/10/12/unit-testing-business-logic-without-tripping-over-the-database /) – dee

答えて

3

を私は同様の問題がありました。

私はから継承されたSqlConnectionオブジェクトとISqlDataContextインタフェース周りSqlDataContextラッパーを導入:

class SqlDataContext : ISqlDataContext { 

    private readonly SqlConnection _connection; 

    public SqlDataContext(string connectionString) 
    { 
     _connection = CreateConnection(connectionString); 
    } 

    public IDataReader ExecuteReader(string storedProcedureName, ICollection<SqlParameter> parameters) 
    { 
     // execute the command here using the _connection private field. 
     // This is where your conn.Open() and "do stuff" happens. 
    } 

    private SqlConnection CreateConnection(string connectionString) 
    { 
     if (string.IsNullOrEmpty(connectionString)) 
     { 
      throw new ArgumentNullException("connectionString"); 
     } 

     return new SqlConnection(connectionString); 
    } 
} 

interface ISqlDataContext 
{ 
    IDataReader ExecuteReader(string storedProcedureName, ICollection<SqlParameter> parameters); 
} 

を必要としてあなたがISqlDataContextにオーバーロードを追加することができます。

これは、Moqなどを使用してモック値を返す必要があるため、ISqlDataContextをモックできることを意味します。

実際にデータベースにヒットせずに、SqlConnectionを通じてデータベースにヒットしたリポジトリなどをテストできます。

その他の利点は、必要に応じてDI/IoCでISqlContextを挿入できることです。 MSTESTと

+0

素晴らしい!私はこれを行ってみましょう – Novastorm

+2

この実装ではIDataReaderの作成を模擬することができますが、 "プールからの接続を取得できません"という行に沿ってエラーメッセージが表示されるようになりました(http: //stackoverflow.com/questions/15848239/how-to-solve-max-connection-pool-error)。これは、SqlConnection(またはSqlCommand)を「廃棄」していないためです。私もIDisposableインターフェイス(https://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx)を実装し、あなたの使用の周りに "using"ステートメントを置くことをお勧めしますこのSqlDataContextオブジェクト。 – Sean

0

Repository Patternを見てください。本質的には、データベースとの会話の実装について心配するのではなく、消費するクラスのデータをモックすることになります。

public class StudentController : Controller 
    { 
     private IStudentRepository studentRepository; 

     public StudentController(IStudentRepository studentRepository) 
     { 
     this.studentRepository = studentRepository; 
     } 

として使用:

public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page) 
    { 
    var students = from s in studentRepository.GetStudents() 
        select s; 

フル例


基本的に、あなたはその後、他のクラスで消費されているリポジトリ

namespace ContosoUniversity.DAL 
{ 
    public class StudentRepository : IStudentRepository, IDisposable 
    { 
     private SchoolContext context; 

     public StudentRepository(SchoolContext context) 
     { 
      this.context = context; 
     } 

     public IEnumerable<Student> GetStudents() 
     { 
      return context.Students.ToList(); 
     } 

     // ... more 

を持っているでしょう上部のリンクにあります。


それでは、あなたのクラスに嘲笑リポジトリ渡します

// arrange 
var mockedRepo = new Mock<IStudentRepository>(); 
// configure 

// act 
var controller = new StudentController(mockedRepo.Object); 
// do stuff 

// assert 
+0

もし私が彼が信じているように直接接続を使用するクラスやメソッドをテストしたいのであれば、彼は困難に遭遇します。 彼がテストしているメソッドは、とにかくリポジトリメソッドであるかのように見えます。 – Graham

+0

彼がリポジトリをテストしたい場合は? – chris31389

0

後半が、なぜない:

[TestMethod] 
MyTestWithInternSqlConnection() 
{ 
    using (ShimsContext.Create()) 
    { 
     // simulate a connection 
     ShimSqlConnection.AllInstances.Open = connection => { }; 
     string commandText; 

     // shim-Mock all called methods 
     ShimSqlCommand.AllInstances.ExecuteReader = command => 
     { 
     commandText = command.CommandText; 
     return new ShimSqlDataReader(); 
     }; 

     int readCount = 0; 
     ShimSqlDataReader.AllInstances.Read = reader => readCount == 0; 
     ShimSqlDataReader.AllInstances.GetSqlStringInt32 = (reader, i) => 
     { 
     readCount++; 
     return "testServer"; 
     }; 

     var theReadedString = AMethodUnderTestThatReadsFromDatabaseAString(); 
     Assert.IsTrue(theReadedString == "testServer"); 
    } 
} 

あなたはSystem.Dataへの参照を追加し、それのためのフェイクを追加する必要があります。

https://msdn.microsoft.com/en-us/library/hh549175.aspx 実装を変更して使用する読み取りレイヤーを変更することができます