BDD «Данный» шаг описания и реализации - PullRequest
2 голосов
/ 25 ноября 2011

Как вы обычно описываете и реализуете «Данный» шаг для сценария?

  1. Описание состояния высокого уровня ИЛИ явные определения данных?
  2. Заполнение базы данных или хранилища заглушек?

Описание состояния высокого уровня

Given I have 4 products
When I look for best-selling products
Then I see top 3 products with maximum number of sales

PRO

  • Не хрупкий
  • Легко читается ипонять бизнес-цель

CON

  • Не ясно, какие данные нам нужны

Явное определение данных

Given I have following products:
  | Name         | Sales number    |
  | Beer         | 20              |
  | Pizza        | 5               |
  | Socks        | 3               |      
  | Toilet paper | 100             |
When I look for best-selling products
Then I see following products:
  | Name         | Sales number    |
  | Toilet paper | 100             |
  | Beer         | 20              |
  | Pizza        | 5               |

PRO

  • Простота реализации (ясно, какие данные необходимы)

CON

  • Трудно читать и понимать бизнесцель
  • Более хрупкие

Заполнить базу данных

using (var connection = new SqlConnection(connectionString))
{                
    using (var deleteCommand = new SqlCommand("DELETE FROM Products", connection))
    {
        connection.Open();
        deleteCommand.ExecuteNonQuery();
    }

    SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Products", connection);              
    DataSet data = new DataSet();
    adapter.Fill(data);

    foreach (var specFlowRow in table.Rows)
    {
        DataRow dataRow = data.Tables[0].Rows.Add();
        dataRow["Name"] = specFlowRow["Name"];                   
    }

    adapter.Update(data);
}

PRO

  • Характеристики какИнтеграционные тесты (мы используем систему end-2-end)

CONS

  • Нам необходимо создать таблицы базы данных до кода (подход на основе данных)
  • Медленный
  • Хрупкий
  • Трудно реализовать

Заглушка репозитория

// or get stubbed repository from DI framework
productsRepository = new InMemoryProductsRepository();            

// or use specflow assist helpers
foreach (var specFlowRow in table.Rows)            
    productsRepository.Save(new Product(specFlowRow["Name"]));

PRO

  • Сначала мы можем сделать код
  • Быстрый
  • Менее хрупкий (легко изменить)
  • Простой в реализации

CONS

  • Мы не делаеместь доказательства того, что эта функция реализована

Это мое видение возможных путей :) Как вы определяете и реализуете «заданные» шаги?Спасибо!

Ответы [ 2 ]

1 голос
/ 25 января 2013

В качестве общего ответа на вопрос «Как мы настраиваем данные для сложных или связанных объектов?» вопрос - как продукты и продажи - все это зависит от того, какое поведение вы указываете. Нет единого, правильного пути. Кстати, вы не включили текст «Особенность» и «Сценарий», чтобы дать нам некоторый контекст для того, для чего предназначен этот кьюк, но, по общему признанию, нетрудно догадаться.

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

Если вы хотели доказать, что дисплей каким-то образом заботится о том, чтобы показывать вещи ранжированными, вы получите более четкие данные, а затем проясните, что вы «перебираете» по объему продаж. Или этот явный пример может показаться как проясняющий, что вы имеете в виду.

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

1 голос
/ 25 ноября 2011

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

Для настройки ваших данных мне лично больше всего нравится ваш пример «явного определения данных».Указание данных, используемых тестами, гарантирует, что вы сможете прочитать тест как документацию.Работа с неизвестным хранилищем данных затрудняет чтение тестов.Но при построении тестовых данных в этом случае название продукта не имеет значения, только сумма.

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

NBuilder - действительно хороший инструмент.Сейчас мы используем его для наших тестов, и он выглядит очень многообещающе.

Ваш тест будет выглядеть так:

class Product
{
    public string Name { get; set; }
    public int Sales { get; set; }
}

[TestMethod]
public void SalesTest()
{
    var products = Builder<Product>.CreateListOfSize(4)
         .TheFirst(1)
         .With(x => x.Sales = 20)
         .AndTheNext(1)
         .With(x => x.Sales = 5)
         .AndTheNext(1)
         .With(x => x.Sales = 3)
         .AndTheNext(1)
         .With(x => x.Sales = 100).Persist();

    var result = SystemUnderTest.Execute();

    Assert.AreEqual(3, result.Count);

    Assert.AreEqual(100, result[0].Sales);
    Assert.AreEqual(20, result[0].Sales);
    Assert.AreEqual(5, result[0].Sales);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...