Модульное тестирование уровня доступа к данным

Я читал о модульном тестировании уровня доступа к данным проекта. Большинство вариантов сводятся к следующему:

  • Используйте выделенную тестовую базу данных, но выполняйте очистку на этапе завершения всех модульных тестов (или делайте это вручную)
  • Использовать базу данных, но не фиксировать или просто откатывать
  • Макет базы данных

В предыдущем проекте мы использовали способ отката, но мне бы хотелось больше узнать о других параметрах и о том, как они лучше всего выполняются. Если у вас есть образцы /статьи /видео /... пожалуйста, поделитесь ими.

7 голосов | спросил Kris van der Mast 28 J000000Wednesday10 2010, 17:30:53

4 ответа


0

Вам необходимо иметь 2 типа тестов с проектом. модульные тесты и интеграционные тесты

Модульные тесты тестируют один аспект вашего проекта без зависимости от доступа к данным и их представления. Для модульных тестов вы должны высмеивать вашу базу данных и внедрение зависимости от пользователя, чтобы отсоединить ваш код от поставщика данных. Это приводит к лучшей архитектуре и позволяет вам подключить другого поставщика данных, если вы того пожелаете. например переход с ADO.net на nHibernate.

Интеграционные тесты - это место, где вы тестируете всю систему и проверяете, что ваш код может получить правильные данные из базы данных и т. д. Для интеграционных тестов у каждого разработчика должна быть копия базы данных на его рабочей станции, с которой они могут тестировать. Вы должны попытаться автоматизировать создание и заполнение вашей базы данных, чтобы вы могли быстро и легко вернуться к хорошей копии базы данных. Такие инструменты, как nant и DBFit поможет вам создать сценарий создания вашей базы данных.

Я бы не стал использовать центральную базу данных для тестирования, так как другие разработчики могут тестировать ее одновременно, и она может быть не в хорошем состоянии, и вы можете получить ложные срабатывания и потратить целую вечность, пытаясь отладить проблему, которая это не проблема.

ответил skyfoot 28 J000000Wednesday10 2010, 17:42:30
0

Я предпочитаю использовать тестовую базу данных вместо идеи не фиксировать .

В моей базе данных dev есть фиктивные записи или полностью обработанная выборка производственных данных.

Моя база данных по интеграционному тестированию является копией действующей рабочей базы данных (эта версия используется для тестирования непосредственно перед выпуском изменений в живую).

ответил Raj More 28 J000000Wednesday10 2010, 17:41:39
0

Основной обязанностью DAL является сохранение /выборка данных из базы данных, поэтому тестируемой системой является DAL + Database. Нет смысла писать тесты на DAL с использованием макета базы данных - кого действительно волнует, какой SQL-запрос был выполнен для извлечения конкретной сущности? Необходимо проверить, был ли выбран правильный объект и правильно ли сопоставлены все атрибуты.

Для этого я обычно очищаю базу данных, заполняю базу тестовыми данными и извлекаю ее методами DAL.

       [SetUp]
    public void SetUp()
    {
        Database.Clear();
        manager = new ServiceManager();
    }

    [TearDown]
    public void TearDown()
    {
        manager.Dispose();
    }

    [Test]
    public void InsertAndLoadOrderContract()
    {
        MinOrderModel model = new OrderBuilder().InsertMinimalOrder(manager);

        Contract contract = TestObjectGenerator.GenerateEntity<Contract>();
        manager.Contract.InsertOrderContract(model.Order.OrderCompositeId, contract);

        Contract selectedContract = manager.Contract.SelectById(contract.ContractId);

        AssertContract(selectedContract, contract);
    }

    private static void AssertContract(IContract actual, IContract expected)
    {
        Assert.That(actual.AgencyCodeOther, Is.EqualTo(expected.AgencyCodeOther));
        Assert.That(actual.AgencyFK, Is.EqualTo(expected.AgencyFK));
        Assert.That(actual.ContractId, Is.EqualTo(expected.ContractId));
        Assert.That(actual.Ident, Is.EqualTo(expected.Ident));
    }

Некоторые части этого теста можно заменить на более удобные:

  1. Можно использовать DbUnit для заполнения пополнение базы данных данными
  2. Не очищать базу данных, а свернуть назад сделка в "TearDown" Метод
  3. Используйте более удобный движок базы данных для тестов (например, SQLLite)
ответил Yauheni Sivukha 30 J000000Friday10 2010, 01:38:16
0

Я бы посмеялся над базой данных. Работа с базой данных в тесте является болезненной, так как вам нужно создать базу данных, создать схему, затем отбросить ее, убедиться, что нет никаких соединений, и т.д. это больно.

Еще одна вещь, которая делает меня неловкой, это то, что проверка вашей логики кода «слишком далека» от кода. Я бы пошел по пути размещения Sql-функций (соединений, команд и т. Д.) За ложным классом и проверил, что DAL вызывает правильные методы. Кроме того, тесты выполняются намного быстрее.

Вот несколько быстрых классов абстракции sql и пример использования + модульный тест.

public class SqlConnectionBase : IDisposable {
    private readonly SqlConnection m_Connection;

    public SqlConnectionBase(string connString) {
        m_Connection = new SqlConnection(connString);
    }

    public virtual SqlConnection Object { get { return m_Connection; } }

    public virtual void Open() {
        m_Connection.Open();
    }
    public virtual void Close() {
        m_Connection.Close();
    }

    #region IDisposable Members

    public virtual void Dispose() {
        m_Connection.Dispose();
    }

    #endregion
}

public class SqlCommandBase  : IDisposable{
    private readonly SqlCommand m_Command;

    public SqlCommandBase() {
        m_Command = new SqlCommand();
    }
    public SqlCommandBase(string cmdText, SqlConnectionBase connection) {
        m_Command = new SqlCommand(cmdText, connection.Object);
    }
    public SqlCommandBase(SqlConnectionBase connection) {
        m_Command = new SqlCommand();
        m_Command.Connection = connection.Object;
    }

    public virtual int ExecuteNonQuery() { return m_Command.ExecuteNonQuery(); }
    public virtual string CommandText { get { return m_Command.CommandText; } set { m_Command.CommandText = value; } }

    public virtual void AddParameter(SqlParameter sqlParameter) {
        m_Command.Parameters.Add(sqlParameter);
    }

    #region IDisposable Members

    virtual public void Dispose() {
        m_Command.Dispose();
    }

    #endregion
}
public class SqlFactory {
    public virtual SqlCommandBase CreateCommand(string query, SqlConnectionBase conn) {
        return new SqlCommandBase(query, conn);
    }
    public virtual SqlCommandBase CreateCommand(SqlConnectionBase conn) {
        return new SqlCommandBase(conn);
    }

    public virtual SqlConnectionBase CreateConnection(string connString) {
        return new SqlConnectionBase(connString);
    }

}

public class DBUser {
   public DBUser(SqlFactory factory) {
     m_factory = factory; //dependency constructor, will be used during unit testing
   }

   public DBUser() {
     m_factory = new SqlFactory(); //used during normal execution
   }

   public void DoSomething() {
     var conn = m_factory.CreateConnection("server=servername,database=...");
     var cmd =  m_factory.CreateCommand(conn);
     cmd.CommandText = "Select * from users";
     cmd.ExecuteNonQuery();
   }

   [TestMethod]
   public void DoSomethingTest() {
     var factoryMock = new Mock<SqlFactory>();
     var cmdMock = new Mock<CommandBase>();
     factoryMock.Setup(f=>f.CreateConnection(It.IsAny<string>())).Returns(cmdMock.Object);
     DBUser dbUser = new DBUser(factoryMock.Object);
     dbUser.DoSomething();

     //Verify that DoSomething is called.
     cmdMock.Verify(c=>c.DoSomething());
   }
}
ответил Igor Zevaka 29 J000000Thursday10 2010, 07:36:06

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132