【问题标题】:May a scenario not have a When in BDD?BDD 中的场景可能没有When 吗?
【发布时间】:2013-12-12 21:22:40
【问题描述】:

我目前正在使用 SpecFlow 学习/测试 BDD,效果很好!

在我选择问我的问题之前,我已经阅读了this one,我觉得我不得不问我的问题,尽管同样的问题已经得到解决,因为Exception 场景是没有提到。

我实际上是在测试这个场景:

Scenario: I should get an error whenever I try to remove an item from an empty stack
    Given I have an empty stack
    When  I pop from it
    Then  I should get an error

public class StackBehaviour {
    public void GivenIHaveAnEmptyStack() { stack = new CustomStack<string>(); }

    // This will throw whenever called!
    // So the Then method will never be run!
    // I feel like I should just put a comment which says why it's empty,
    // allowing a fellow programmer to understand the exact intention.
    public void WhenIPopFromIt() { stack.Pop(); }

    // It is here that it verifies whether the CustomStack meets the expected behaviour.
    public void ThenIShouldGetAnError() {
        Assert.Throws<IndexOutOfRangeException>(delegate {
            stack.Pop(); 
        });
    }

    private CustomStack<string> stack;
}

public class CustomStack<T> {
    public T Pop() { 
        if (stack.Count == 0) 
            throw new IndexOutOfRangeException("Cannot pop from an empty stack!");
        T item = stack[stack.Count-1];
        stack.RemoveAt(stack.Count-1);
        return item;
    }

    private ArrayList stack = new ArrayList();
}

我认为在When方法中留下评论是正确的,这样业务需求不会缺少任何信息,并且在后面的代码上,我通过评论明确了我的意图。

你怎么看?任何其他想法为什么我不应该这样做?

【问题讨论】:

  • 提供的两个答案都很棒!我现在很难选择接受哪个作为我问题的答案,因为它们以不同的方式解决问题,并且两个答案可能彼此一样好。首先,我知道我想要一个错误,所以只需相应地编码When。我完全同意!其次,技术问题,例如将 null 压入堆栈,不应该与涉众无关,因为它更可能是技术问题,这在 BDD 和 TDD 之间划清了界限。我完全同意!
  • @Alski 的回答确实显示了如何使用 SpecFlow 来测试这个 CustomStack,但是我仍然觉得使用 BDD 框架来单独测试单个组件是过度的。 BDD 通常用于描述用户如何与系统交互;在您的示例中,用户不会直接从堆栈中弹出一个项目,而是他们会在应用程序中执行一个使用 CustomStack 的操作,然后触发堆栈的弹出。因此,我认为使用 TDD 和单元测试更好地测试 CustomStack 的原因。看看 Alski 的想法会很有趣。
  • 我完全同意,Fresh。在现实世界中,BDD 代表对整个系统的行为进行测试。因此,严格来说 BDD,您的答案是真正解决方案的最佳选择。此外,Alski 的回答满足了本教程的需求,即能够同时使用发生动作的When 和应针对预期值/行为进行测试的Then。我的困境在于 Alski 的回答所暗示的,这解决了我的问题,而且我们确实看到了 BDD 和 TDD 之间的界限,因为事实上,这些异常不属于 BDD,而是属于 TDD。
  • 我在学习如何使用 BDD 以及如何不使用它方面经历了一段旅程,最近我搬到了一个与我有相同观点的团队。但是,我绝对建议您自己经历类似的旅程,以找到 BDD 和 TDD 之间的正确平衡。只是告诉你不会帮助你理解为什么必然。
  • 我开始大量使用 BDD。最初我几乎只使用它,就像你一样替换单元测试。后来我开始看到 NUnit 测试可以更快地编写,因此开始尝试构建结合 GWT 步骤进行单元测试的测试框架,但这是徒劳的练习,只是生成了更多的测试代码。

标签: bdd specflow gherkin scenarios


【解决方案1】:

您可以使用另一个技巧,绑定有助于使功能的含义更加清晰。在这种情况下,让我们从头开始。

Then I should get an error

你的问题基本上在这里,你知道想要一个错误,但你不知道如何得到它。事实上,您已经错过了它,错误已经发生在 When 步骤中,并且在您的代码示例中,您将操作移到了 then 步骤中,这样您就可以得到错误。

但是如果让when 继续执行操作并重新表达我们的then 以反映实际发生的情况会怎样

Then I should have had an error

似乎是一个微不足道的更改,但现在我们的功能反映了错误应该与When 步骤相关联,我们稍后只是对其进行评估,这是我们可以编写的代码。我们只需要记住when 中的错误并将其传递给then。

private Exception errorFromWhen = null;

public void WhenIPopFromIt() 
{ 
  try
  {
    stack.Pop(); 
  }
  catch(Exception ex)
  {
     errorFromWhen = ex;
  }
}

public void ThenIShouldGetAnError() 
{
   errorFromWhen.ShouldNotBeNull();
   errorFromWhen.ShouldBe<IndexOutOfRangeException>();
}

SpecFlow 对此完全没有问题,事实上由于它的mini Dependency injection system,如果需要,您甚至可以在绑定类之间传递此状态。

【讨论】:

  • +1 感谢您的回答,这绝对是有道理的!我会考虑这个并立即尝试。
【解决方案2】:

BDD 中的场景可能没有When?

在 Specflow 中,无论是给定、何时还是那么都不是强制性的。

但是在您的示例中,我不认为这是对 Specflow 和 BDD 的良好使用。在这个答案中,马库斯说:

"BDD is about ensuring that we're building the right thing, TDD is about ensuring that we're building it right."

在您的示例中,应通过 TDD 测试正在测试的范围,即 CustomStack。它是使用 CustomStack 的最终解决方案,应该通过 BDD(以及因此 SpecFlow)进行测试,例如如果此 CustomStack 是通过网站上的某个操作执行的。

This的回答也与你的问题有关。

【讨论】:

  • +1 感谢您提供这些见解。我理所当然地认为单元测试项目仍然是相关的,尽管也使用了 BDD。这划定了 BDD 和 TDD 之间不交叉的界限。另外,我正在关注这篇有趣的文章,它测试了堆栈的行为,假设利益相关者想要一个堆栈对象,所以我想知道哪条线不能跨越。 ibm.com/developerworks/java/library/j-cq09187/index.html
  • 感谢您的回答。我真的从中学到了很多。请参阅我与我的问题相关的最后评论,以便您知道我为什么接受 Alski 的回答。如果您觉得我的判断有问题,请随时说出来,我会考虑重新考虑我的接受情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多