Как выполнить модульное тестирование объекта с запросами к базе данных

141
задан Teifion 27 August 2008 в 17:46
поделиться

12 ответов

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

для установки объектов для насмешки, вероятно, необходимо использовать своего рода инверсию управления / шаблон внедрения зависимости, как в следующем псевдокоде:

class Bar
{
    private FooDataProvider _dataProvider;

    public instantiate(FooDataProvider dataProvider) {
        _dataProvider = dataProvider;
    }

    public getAllFoos() {
        // instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction
        return _dataProvider.GetAllFoos();
    }
}

class FooDataProvider
{
    public Foo[] GetAllFoos() {
        return Foo.GetAll();
    }
}

Теперь в Вашем модульном тесте, Вы создаете насмешку для FooDataProvider, который позволяет Вам называть метод GetAllFoos, не имея необходимость на самом деле поражать базу данных.

class BarTests
{
    public TestGetAllFoos() {
        // here we set up our mock FooDataProvider
        mockRepository = MockingFramework.new()
        mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);

        // create a new array of Foo objects
        testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()}

        // the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos,
        // instead of calling to the database and returning whatever is in there
        // ExpectCallTo and Returns are methods provided by our imaginary mocking framework
        ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)

        // now begins our actual unit test
        testBar = new Bar(mockFooDataProvider)
        baz = testBar.GetAllFoos()

        // baz should now equal the testFooArray object we created earlier
        Assert.AreEqual(3, baz.length)
    }
}

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

75
ответ дан gcb 27 August 2008 в 17:46
поделиться
  • 1
    @Peter Burns: С SVN у Вас почти всегда есть один из авторов, делающих слияние. С Git/Hg/etc слияние может быть сделано кем-то кто didn' t пишут любую сторону. I' ll редактируют для создания этого более ясным. – BCS 20 January 2009 в 17:25

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

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

В моих c# проектах, я использую NHibernate с абсолютно отдельным уровнем Data. Мои объекты живут в базовой модели предметной области и получены доступ от моего прикладного уровня. Прикладной уровень говорит и со слоем данных и со слоем модели предметной области.

прикладной уровень также иногда называют "Бизнес-Слоем".

при использовании PHP создайте определенный набор классов для [ТОЛЬКО 116] доступ к данным. Удостоверьтесь, что Ваши объекты понятия не имеют, как они сохраняются и обеспечивают электричеством два в Ваших классах приложений.

Другая опция состояла бы в том, чтобы использовать насмешку/тупики.

25
ответ дан Sean Chambers 27 August 2008 в 17:46
поделиться
  • 1
    Я все еще не соглашаюсь с Вашим новым сообщением. Единственное время слияние сделано в мерзавце и др., когда you' ре, явно объединяющее два расходящихся дерева. Правда, SVN вынуждает автора объединиться, прежде чем он будет фиксировать, но если Вы используете ответвления в SVN, тогда у Вас есть тот же потенциал для слияния, которое будет сделано третьим лицом. – Peter Burns 20 January 2009 в 20:32

Самый легкий путь к модульному тесту объект с доступом к базе данных использует области транзакций.

, Например:

    [Test]
    [ExpectedException(typeof(NotFoundException))]
    public void DeleteAttendee() {

        using(TransactionScope scope = new TransactionScope()) {
            Attendee anAttendee = Attendee.Get(3);
            anAttendee.Delete();
            anAttendee.Save();

            //Try reloading. Instance should have been deleted.
            Attendee deletedAttendee = Attendee.Get(3);
        }
    }

Это вернется назад состояние базы данных, в основном как откат транзакции, таким образом, можно будет запускать тест так много раз, как Вы хотите без любого sideeffects. Мы использовали этот подход успешно в крупных проектах. Наша сборка действительно занимает много времени немного для выполнения (15 минут), но это не ужасно для того, чтобы иметь 1 800 модульных тестов. Кроме того, если время изготовления является беспокойством, можно изменить процесс сборки для имения нескольких сборок, один для создания src, другой, который разжигает впоследствии, который обрабатывает модульные тесты, анализ кода, упаковку, и т.д.

11
ответ дан BZ. 27 August 2008 в 17:46
поделиться
  • 1
    Хорошо, I' m ясно лупящий мою точку, таким образом, это - последний комментарий I' ll делают. Третье лицо, объединяющее два других people' s код часто плохая идея и распределенный VCSs don' t должен сделать это. I' ve использовал мерзавца в течение года, но I' ve никогда не должен был объединять два других people' s кодируют вместе, и при этом я не видел это. – Peter Burns 13 February 2009 в 04:58

Книга xUnit Тестовые Шаблоны описывает некоторые способы обработать код поблочного тестирования, который поражает базу данных. Я соглашаюсь с другими людьми, которые говорят, что Вы не хотите делать это, потому что это медленно, но необходимо сделать это когда-то, IMO. Насмешка соединения дб для тестирования высокоуровневого материала является хорошей идеей, но проверьте эту книгу для предложений о вещах, которые можно сделать для взаимодействия с фактической базой данных.

6
ответ дан Chris Farmer 27 August 2008 в 17:46
поделиться

Опции Вы имеете:

  • Запись сценарий, который вытрет базу данных перед запуском модульных тестов, затем заполните дб с предопределенным набором данных и запустите тесты. Можно также сделать это перед каждым тестом – это будет медленно, но менее подвержено ошибкам.
  • Вводят базу данных. (Пример в псевдо-Java, но относится ко всем языкам OO)

    class Database {
     public Result query(String query) {... real db here ...}
    }
    
    

    class MockDatabase extends Database { public Result query(String query) { return "mock result"; } }

    class ObjectThatUsesDB { public ObjectThatUsesDB(Database db) { this.database = db; } }

    теперь в производстве, Вы используете нормальную базу данных, и для всех тестов Вы просто вводите ложную базу данных, которую можно создать для данного случая.
  • не используют DB вообще всюду по большей части кода (это - плохая практика так или иначе). Создайте объект "базы данных", который вместо того, чтобы возвратиться с результатами возвратит обычные объекты (т.е. возвратится User вместо кортежа {name: "marcin", password: "blah"}), пишут все Ваши тесты со специальным, созданным реальный объекты, и пишут один большой тест, который зависит от базы данных, которая удостоверяется это преобразование работы хорошо.

, Конечно, эти подходы не являются взаимоисключающими, и Вы можете смешивание и подгонка их, как Вам нужно.

4
ответ дан Marcin 27 August 2008 в 17:46
поделиться

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

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

9
ответ дан Martin Klinke 27 August 2008 в 17:46
поделиться

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

Мы сначала создали уровень абстракции, который позволил нам "слоту в" любом разумном соединении с базой данных (в нашем случае, мы просто поддерживали единственное соединение типа ODBC).

, Как только это существовало, мы тогда смогли сделать что-то вроде этого в нашем коде (мы работаем в C++, но я уверен, что Вы получаете идею):

GetDatabase ().ExecuteSQL ("нечто INSERT INTO (вздор, вздор)")

В нормальное время выполнения, GetDatabase () возвратил бы объект, который подал весь наш sql (включая запросы) через ODBC непосредственно к базе данных.

Мы тогда начали смотреть на базы данных в оперативной памяти - лучшее длинным путем, кажется, SQLite. ( http://www.sqlite.org/index.html ). Это удивительно просто настроить и использовать, и позволило нам подкласс и переопределение GetDatabase () для передачи sql базе данных в оперативной памяти, которая была создана и уничтожена для каждого выполненного теста.

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

В целом, помогло очень с нашим процессом TDD, начиная с создания, что кажется, что довольно безвредные изменения для исправления определенных ошибок могут иметь довольно странное влияние на другом (трудный обнаружить) области системы - из-за самой природы sql/databases.

, Очевидно, наши события центрировались вокруг среды разработки C++, однако я уверен, что Вы могли, возможно, получить что-то подобная работа под PHP/Python.

Hope это помогает.

9
ответ дан Alan 27 August 2008 в 17:46
поделиться

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

, Например, модульный тест Ваш пользовательский интерфейс при классификации тестов Вы пишете, должен только попытаться проверить, что логика в UI работала как ожидалось, не бизнес-логика или действие базы данных позади той функции.

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

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

Жаль у меня нет определенных примеров кода для PHP/Python, но если Вы хотите видеть пример.NET, я имею сообщение , который описывает технику, я раньше делал это очень то же тестирование.

3
ответ дан Community 27 August 2008 в 17:46
поделиться
2
ответ дан codeLes 27 August 2008 в 17:46
поделиться
  • 1
    +1 для Kaminari. Я использовал will_paginate, но Kaminari намного более хорош. – kakubei 27 June 2012 в 10:17

Я обычно пытаюсь разбить свои тесты между тестированием объектов (и ORM, если таковые имеются) и тестированием дб. Я тестирую объектную сторону вещей путем насмешки вызовов доступа к данным, тогда как я тестирую сторону дб вещей путем тестирования объектных взаимодействий с дб, который, по моему опыту, обычно справедливо ограничивается.

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

2
ответ дан akmad 27 August 2008 в 17:46
поделиться
  • 1
    Я пришел к тому же заключению. railscasts учебное руководство на will_paginate было тихо полезный также. – tstyle 27 April 2011 в 07:49

Вы могли использовать платформы насмешки для абстракции механизма базы данных. Я не знаю, получил ли PHP/Python некоторых, но для типизированных языков (C#, Java и т.д.) существует много выбора

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

2
ответ дан chakrit 27 August 2008 в 17:46
поделиться
  • 1
    Ну, предыдущей вещью, которую я использовал, был will_paginate, который раньше был значением по умолчанию paginator. Красота searchlogic состоит в том a) что все интегрируется (Вы don' t должны добраться, paginator сотрудничают, фильтруя/сортируя, это сделано автоматически/волшебно). И b) it' s симпатичный активно разработанный банкомат и это выглядит довольно зрелым. c) разработчиком, производит очень хорошие и интуитивные библиотеки, я также рекомендовал бы его подлинную библиотеку ' authlogic'. в документации you' ll находят некоторые комментарии, почему authlogic является ' better' чем другие подлинные плагины:). Но просто испытайте их в одном из Ваших представлений данных.. – reto 9 June 2009 в 08:03

Я соглашаюсь с первым сообщением - доступ к базе данных должен быть снят на уровень DAO, который реализует интерфейс. Затем можно протестировать логику против тупиковой реализации уровня DAO.

2
ответ дан Chris Marasti-Georg 27 August 2008 в 17:46
поделиться
  • 1
    Как это выдерживает сравнение с многочисленными другими решениями для разбиения на страницы? Почему предпочитают это другим? – propstop 8 June 2009 в 22:52
Другие вопросы по тегам:

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