开发者

Any suggestions for improvement on this style for BDD/TDD?

I was tinkering with doing the setups with our unit test specifciations which go like

Specification for SUT when behaviour X happens in scenario Y Given that this thing And also this other thing When I do X... Then It should do ... And It should also do ...

I wrapped each of the steps of the GivenThat in Actions... any feed back whether separating with Actions is good / bad / or better way to make the GivenThat clear?

        /// <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,
                                         ProductT开发者_如何学编程ype =
                                             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();
        }


Put them in separate methods so that you can compose them in other givens. Also, use underscores to replace spaces (instead of camel case). Also, create a method Given_that that takes params of Action delegates.

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);

That being said, I think the naming of your preconditions are not BDD. They are very technical in nature and do not denote the business need. If you were to tell a non-programmer what you were testing, you would probably not say "the product is stubbed for injection." You would more likely say

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

Now you can compose your "given" methods with little duplication:

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);


Composing your Givens, Whens and Thens in separate methods is a good idea and it's the way for instance SpecFlow (http://www.specflow.org) does it. So if rather want some automation for creating that boring piece of repetetive plumbing, I would really recomend using a tool like SpecFlow. And as a bonus you get a nice reporting tool :)

An other option to make your code a bit more fluent, is to make a little BDD base class. Take a look at Jonas Follesoe's brilliant little BDD DSL up at 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; } }
}

And as Michael Meadows point out in his great answer; If you're going the BDD way of doing TDD (which you really should), keep focus on making your spesifications readable to business people. That means; stay away from technical wordings mock, inject, factory, exception, etc.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜