C # Передача макетного объекта классу, который проверяет / проверяет тип параметра

#c# #unit-testing #generics #inheritance #mocking

#c# #модульное тестирование #общие сведения #наследование #насмешливый

Вопрос:

У меня есть универсальный класс, SqlDataImporter который считывает данные из источника данных SQL. Вот некоторые из его методов:

         #region properties

        protected IDbConnection DbConnection; // Maintain this connection
        protected IDataReader DataReader; // Used to import data via the DbConnection
        protected DataTable DataSegment;

        #endregion

        #region constructors

        protected SqlDataImporter(IDbConnection importConnection, string importQuery)
        {
            ValidateConstructorArguments(importConnection, importQuery); // throws exception if invalid

            this.DbConnection = importConnection;

            InitialiseDataReader(importQuery);
        }

        #endregion

        #region methods

        protected void ValidateConstructorArguments(IDbConnection importConnection, string importQuery)
        {
            if (String.IsNullOrEmpty(importQuery))
            {
                string msg = "Provided importQuery has null or empty value. A query must be provided for importing data.";
                throw new ArgumentException(msg);
            }
        }

        private void InitialiseDataReader(string importQuery)
        {
            if (this.DbConnection.State != ConnectionState.Open)
                this.DbConnection.Open();

            using (IDbCommand command = this.DbConnection.CreateCommand())
            {
                command.CommandTimeout = 1200;
                command.CommandText = importQuery;

                this.DataReader = command.ExecuteReader();
            }

            if (this.DataReader == null) // only reason this could happen is source doesn't exist?
                throw new Exception("Source does not exist: "   importQuery);
        }
 

Идея заключается в том, что этот класс является достаточно общим для чтения как из источника данных Postgresql (с использованием переданного OdbcConnection), так и из источника данных Sql Server (с использованием переданного SqlConnection). Тип переданного соединения определяет тип IDataReader созданного из-за содержимого InitialiseDataReader() метода.

Затем я создал 2 дочерних класса PostgreSqlImporter , SqlServerImporter которые будут использоваться при чтении из разных источников. Они оба наследуются от этого родительского класса. На самом деле вся работа выполняется в родительском SqlDataImporter классе, чтобы уменьшить дублирование.

Все, что делают дочерние классы, это вызывают этот метод ValidateConstructorArguments() и проверяют, что переданные соединения имеют ожидаемый тип (OdbcConnection или SqlConnection в зависимости от класса). Например:

  public SqlServerImporter(IDbConnection importConnection, string importQuery) : base(importConnection,  importQuery)
        {
            ValidateConstructorArguments(importConnection);
        }



        protected void ValidateConstructorArguments(IDbConnection importConnection)
        {
            if (importConnection.GetType() != typeof(SqlConnection))
            {
                string msg = "Provided importConnection must be of type SqlConnection. Actual type is "   importConnection.GetType();
                throw new ArgumentException(msg);
            }
        }
 
 

Первоначально я сделал параметр подключения универсальным типом IDBConnection , потому что хотел иметь возможность передавать макет объекта в качестве параметра из моих модульных тестов. Но теперь я добавил этот код, чтобы проверить тип переданного соединения ( ValidateConstructorArguments(IDbConnection importConnection) ) Я получаю свое собственное исключение ArgumentException, когда я передаю издевательский объект: System.ArgumentException: Provided importConnection must be of type SqlConnection. Actual type is Castle.Proxies.IDbConnectionProxy

Теперь я заблудился. Я все еще хочу иметь возможность передавать макетные объекты для тестирования, но не могу проверить тип времени выполнения соединения, если захочу это сделать. Если я откажусь от проверки типа соединения, то мне интересно, есть ли смысл иметь эти два дочерних класса (PostgreSqlImport и SqlServerImporter).

  • Должен ли я отказаться от двух дочерних классов и проверки типа соединения во время выполнения? Не кажется надежным делать это…
  • Должен ли я добавить код к ValidateConstructorArguments методу, чтобы игнорировать тип, если это фиктивный тип?
  • Является ли мой дизайн ошибочным?

Комментарии:

1. Какой тип драйвера вы планируете использовать? ODBC и OleDb — это разные общие спецификации для интерфейса с базами данных. Я не уверен, какой тип использует Net SqlClient. Для SqlClient у вас может быть несколько различных типов драйверов (см. : connectionstrings.com/sql-server ). Я думаю, вам нужно определить драйвер, который будет возвращать тип.

2. @jdweng немного выходит за рамки моих знаний, но я планирую использовать ODBC полностью, потому что он уже использовался ранее в кодовой базе. Я не уверен, как будет выглядеть определение драйвера, который возвращает тип. Имейте в виду, что планируется, чтобы этот код существовал в задаче сценария SSIS с ограниченными библиотеками и зависимостями.