web-dev-qa-db-ja.com

MoqとSqlConnection?

私たちの製品の1つに対する単体テストを書いており、Moqを使用してEntity Frameworkへの接続を正常にモックしています。しかし、私は次の方法に出くわしました:

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

渡された接続文字列を使用して、そのメソッド内でデータベースにアクセスします。 Moqを使用して模擬DBをセットアップし、模擬DBを指す接続文字列を作成することは可能ですか?私はの線に沿って何かをやってみました

var mockSqlConnnection = new Mock<SqlConnection>();

これが正しいアプローチであるかどうかはわかりませんが、これはDBではなく接続自体をモックするからです。

13
Novastorm

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

SqlDataContextインターフェイスから継承したSqlConnectionを囲むISqlDataContextラッパーを導入しました。

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を介してリポジトリまたはデータベースにアクセスする他の何かをテストできます。

もう1つの利点は、必要に応じてISqlContextにDI/IoCを注入できることです。

10
Graham

遅いが、なぜmstestを使用しないのか:

[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への参照を追加してから、Fakeを追加する必要があります。

https://msdn.Microsoft.com/en-us/library/hh549175.aspx 実装を変更し、使用する読み取り層を変更できる場合は...

6
tire0011

Repository Pattern をご覧ください。基本的に、データベースと通信する実装を心配するのではなく、消費するクラスのデータをモックするでしょう。


基本的に、リポジトリがあります

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

これは他のクラスで消費されます:

   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;

完全な例は、上部のリンクにあります。


そのため、模擬リポジトリをクラスに渡します。

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

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

// assert
1
NikolaiDante