BDD和"何时"的位置

pon*_*tic 5 bdd

我已经看到了我认为BDD的两种方法.差异取决于"何时"的位置:

在方法1中,when是规范的一部分:

AnEmptyStack.isNoLongerEmptyAfterPush
Run Code Online (Sandbox Code Playgroud)

在纯粹的"当时给定"术语中,这是:

"给定一个空堆栈,当它被推动时,它就不再是空的."

所以"when"是规范方法的一部分:

isNoLongerEmptyAfterPush(){
     stack.push(anObject);
     Assert.notEmpty(stack);
}
Run Code Online (Sandbox Code Playgroud)

在方法2中,when在类级别定义.也就是说,通常在设置中调用when.

class WhenAnEmptyStackIsPushed(){

   setup(){
      stack.push();
   }

   public void thenItIsNotEmpty(){
      assert(stack.notEmpty())
   }
}
Run Code Online (Sandbox Code Playgroud)

有首选方法吗?就纯行为测试而言,第二种选择对我来说似乎更为可取,因为测试夹具的重点在于行为.

但是,为了便于测试,我倾向于第一种方法.我在测试中发现的大部分痛苦都是设置.也就是说,我必须在特定状态下获得SUT.一旦进入该状态,通常只需要一行代码来实际调用它上面的某些行为.因此,每个类具有多个行为(即,每个设置上下文)利用该类的一次性设置.

所以,我正在寻找想法.一种方法比另一种方法更受欢迎吗?

Jay*_*Jay 2

根据您的测试框架,您也许可以两全其美。

当我围绕 sut 创建一组测试时,我首先声明一个类来包装整套规范,然后声明一个抽象类:

public class SomethingDoerSpecs
{

    public abstract class concern : observations_for_a_sut_with_a_contract<IDoSomething,SomethingDoer>
    {
        // here I can define setup that will be common to all subsequent tests
        context c = () => ...
    }

    public class When_asked_to_do_something : concern
    {
        context c = () =>
        {
            // setup specific to this context goes here
        };

        because b = () => sut.DoSomething();

        it should_open_a_database_connection =
             () => mock_db_connection.was_told_to(x => x.Open());

        it should_set_the_result_value_to_true =
             () => sut.Result.should_be_true();

        // etc.
    }

   public class When_asked_to_do_something_but_the_database_is_unavailable
        : When_asked_to_do_something
    {
       context c = () =>
         {
            // additional context
         };

         because b = doing(() => sut.DoSomething());

         it should_throw_a_custom_exception = () =>
         {
            exception_thrown_by_the_sut.should_not_be_null();
             exception_thrown_by_the_sut
                 .should_be_an_instance_of<CouldNotDoSomethingException>();
         };

    }
}
Run Code Online (Sandbox Code Playgroud)

这只是为了说明测试类通常可以嵌套,因此您仍然可以执行“大”When... 并在需要更大的上下文特异性时重用之前通过继承设置的状态。当然,您必须确保您的框架将重置断言集之间的设置。

顺便说一句,我在这里展示的整个委托语法来自 Jean-Paul Boodhoo 的 DevelopWithPassion.Bdd 库,您可以在 Github 上找到该库。