Любые предложения по улучшению этого стиля для BDD / TDD? - PullRequest
3 голосов
/ 21 мая 2010

Я возился с настройками нашего модульного теста, которые выглядят как

Спецификация для SUT, когда поведение X происходит в сценарии Y Учитывая, что эта вещь А также эта другая вещь Когда я делаю X ... Тогда это должно сделать ... И это также должно сделать ...

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

        /// <summary>
        /// Given a product is setup for injection
        ///     And Product Image Factory Is Stubbed();
        ///     And Product Size Is Stubbed();
        ///     And Drawing Scale Is Stubbed();
        ///     And Product Type Is Stubbed();
        /// </summary>
        protected override void GivenThat()
        {
            base.GivenThat();

            Action givenThatAProductIsSetupforInjection = () =>
              {
                  var randomGenerator = new RandomGenerator();

                  this.Position = randomGenerator.Generate<Point>();

                  this.Product = new Diffuser
                                     {
                                         Size =
                                             new RectangularProductSize(
                                             2.Inches()),
                                         Position = this.Position,
                                         ProductType =
                                             Dep<IProductType>()
                                     };
              };

            Action andProductImageFactoryIsStubbed = () => Dep<IProductBitmapImageFactory>().Stub(f => f.GetInstance(Dep<IProductType>())).Return(ExpectedBitmapImage);

            Action andProductSizeIsStubbed = () =>
                 {
                     Stub<IDisplacementProduct, IProductSize>(p => p.Size);

                     var productBounds = new ProductBounds(Width.Feet(), Height.Feet());

                     Dep<IProductSize>().Stub(s => s.Bounds).Return(productBounds);
                 };

            Action andDrawingScaleIsStubbed = () => Dep<IDrawingScale>().Stub(s => s.PixelsPerFoot).Return(PixelsPerFoot);

            Action andProductTypeIsStubbed = () => Stub<IDisplacementProduct, IProductType>(p => p.ProductType);

            givenThatAProductIsSetupforInjection();
            andProductImageFactoryIsStubbed();
            andProductSizeIsStubbed();
            andDrawingScaleIsStubbed();
            andProductTypeIsStubbed();
        }

Ответы [ 2 ]

2 голосов
/ 21 мая 2010

Поместите их в отдельные методы, чтобы вы могли составить их в других данностях. Кроме того, используйте подчеркивание для замены пробелов (вместо верблюжьего падежа). Также создайте метод Given_that, который принимает параметры Action делегатов.

protected void Given_that(params Action[] preconditions)
{
    foreach (var action in preconditions)
    {
        action();
    }
}

...

protected void a_product_is_set_up_for_injection()
{
    ...
}

protected void product_image_factory_is_stubbed()
{
    ...
}

etc...

...

Given_that(a_product_is_set_up_for_injection,
           product_image_factory_is_stubbed,
           product_size_is_stubbed,
           drawing_scale_is_stubbed,
           product_type_is_stubbed);

При этом, я думаю, что названия ваших предварительных условий не являются BDD. Они носят технический характер и не обозначают потребности бизнеса. Если бы вы сказали непрограммисту, что вы тестировали, вы бы, вероятно, не сказали «продукт заглушен для инъекции». Вы бы скорее сказали

Given a displacement product
    that is a two inch rectangular diffuser
    that has a random position
    that has a bitmap
    that has a size bounded by feet
    that has the expected pixels per foot

Теперь вы можете составлять ваши "данные" методы с небольшим дублированием:

protected [the type of your test class] Given(params Action given)
{
    given();
    return this;
}

protected void That(params Action[] preconditions)
{
    foreach (var precondition in preconditions)
    {
        precondition();
    }
}

Given(a_displacement_product)
    .That(is_a_two_inch_rectangular_diffuser,
          has_a_random_position,
          has_a_bitmap,
          has_a_size_bounded_by_feet,
          has_the_expected_pixels_per_foot);
1 голос
/ 24 мая 2010

Составление ваших Givens , Когда и Thens в отдельных методах - хорошая идея, и именно так, например, SpecFlow (http://www.specflow.org) делает это. Так что, если вам нужна автоматизация для создания этого скучного кусочка водопроводной трубы, я бы действительно рекомендовал использовать такой инструмент, как SpecFlow. И в качестве бонуса вы получите хороший инструмент отчетности:)

Другой вариант сделать ваш код немного более беглым - создать небольшой базовый класс BDD. Взгляните на блестящего маленького BDD DSL Джонаса Фоллезо на GitHub: http://gist.github.com/406014;

public abstract class BDD<T> where T : BDD<T>
{
    protected T Given { get { return (T)this; } }
    protected T And { get { return (T)this; } }
    protected T When { get { return (T)this; } }
    protected T Then { get { return (T)this; } }
}

И как Майкл Медоус указал в своем великом ответе; Если вы собираетесь использовать BDD для TDD (что вам действительно нужно), продолжайте сосредотачиваться на том, чтобы сделать ваши спецификации понятными для деловых людей. Это означает; держаться подальше от технических формулировок: макет, ввод, фабрика, исключение и т. д.

...