【问题标题】:BDD in .NET - A Trivial Challenge With Exceptions.NET 中的 BDD - 有异常的小挑战
【发布时间】:2012-08-14 11:00:11
【问题描述】:

编辑:为我自己的理智更新了 21/09/12...我不敢相信这曾经是一个问题(耶学习)。

这个控制台元素让我有点远离了这个气味。如果我只是想检查错误,而不是特别是消息,那么只是断言(期望)异常可能会起作用。记录控制台活动并检查日志会起作用。帖子末尾详细介绍的系统响应想法会奏效。这种事情有很多选择。吨!我的结论?做任何最有意义/最不脆弱的事情。只要您的场景是可靠的并且您正在证明行为,一切都很好。


我的 BDD 任务继续使用 .NET 中的一个简单的控制台应用程序(VS2010、SpecFlow 和 NUnit)。

我遇到了这样的场景:

Feature: Withdraw Money
Scenario: Insufficient Funds
Given I have a MoneyBox
And my MoneyBox contains £10
When I withdraw £20
Then the system should display an error message
And my MoneyBox should contain £10

定义上下文很好,尝试提取资金很好。所有相关的单元测试都很好。最后保持平衡很好。

我想实现一些这样的 .Withdraw() 方法:

//Assume the moneybox only contains £1 coins (hence int is ok)
public void Withdraw(int withdrawlAmount) throws InsufficientFundsException
{
if(this.balance >= withdrawlAmount)
{
this.balance -= withdrawlAmount;
}
else
{
throw new InsufficientFundsException();
}
}

我可以对该代码进行单元测试(通过通过和失败条件测试)。

但是,在控制台应用程序的上下文中,我不太清楚如何断言:

Then the system should display an error message

任何想法、提示或参考将不胜感激。

编辑1:

注意我的问题仅涉及通过使用 BDD 方法的验收测试来证明错误消息。感觉是语境问题。再次感谢。

编辑2:

一种方法可能是重新考虑场景,或者更确切地说是它的实施。 MoneyBox 代码可以按原样编写(经过单元测试,未经验收测试的纯 BO),但它的功能可以包装在某个上下文类中:

超级快速示例:

public class MoneyBoxDriver
{
private MoneyBox objMB
private SystemResponse objSR

//Standard stuff e.g. constructor

private void Withdraw(int withdrawAmount)
{
try
{
objMB.Withdraw(withdrawAmount);
}
catch(InsufficientFundsException)
{
this.objSR = new SystemResponse(SystemResponseEnum.FailedInsufficientFunds);
}
}

然后我们可以将 MoneyBoxDriver 设置为上下文,通过 Withdraw 包装器方法对其进行操作,然后通过检查 MoneyBoxDriver 的 SystemResponse 来断言功能。

Then the system should display an insufficient funds error message
...
Assert.That(MBDriver.SystemResponse.Type == SystemResponseEnum.FailedInsufficientFunds)
...

如果 SystemResponse 属于给定类型,则在 UI(控制台)中可能有简单的代码来显示错误消息。

【问题讨论】:

  • 在你的 else 语句中,有一个MessageBox.Show("You do not have enough money for the transaction");
  • 感谢您的回复,但考虑到 .Withdraw() 方法将在 MoneyBox 类中,我会非常不舒服将任何与 MessageBox 或其他 UI 组件有关的东西放在那里,即使在这个简单的例子。这个想法是,这是作为一个学习过程的更大图景的可扩展示例。就错误消息的格式而言,控制台应该只显示一个字符串。
  • 抱歉,我误解了您的问题。如果你只想让conole显示一个字符串,Console.Write("You do not have enough money for the transaction");会不起作用吗?
  • 没关系,如果不清楚,我很抱歉 - 感谢您的意见。重申一下,我的问题不是关于如何编写这个基本功能(Console.Writeline 肯定会工作)。相反,我想确定如何使用 BDD 方法通过验收测试来证明它。

标签: .net exception console tdd bdd


【解决方案1】:

这是任何类型的测试优先方法的乐趣的一部分,它将迫使您以一种可以测试的方式设计您的对象 - 而且他们会因此而变得更好!

在此示例中,我会考虑执行以下操作: (请注意,以下代码未经测试,也不是“完美”解决方案 - 但它更可测试,更接近您想要的位置)。

//Assume the moneybox only contains £1 coins (hence int is ok)
public void Withdraw(int withdrawlAmount, Action<InsufficientFundsException> handleException)
{
     if(this.balance >= withdrawlAmount)
     {
          this.balance -= withdrawlAmount;
     }
     else
     {
          handleException(new InsufficientFundsException());
     }
}

然后您可以在您的测试代码中为可能的异常设置一个字段或属性,当您调用 Withdraw 方法时只需指定一个快速操作来执行回调,例如:

moneyBox.Withdraw(10, e => this.WithdrawException = e);

然后您的Then 语句可以断言WithdrawException 不为空,并对其中的消息进行断言。

您的生产代码(即控制台应用程序)可能会这样做:

moneyBox.Withdraw(10, e => Console.WriteLine("Error: {0}", e.Message));

更完美的解决方案是将Action&lt;InsufficientFundsException&gt; 替换为Action&lt;MoneyBoxWithdrawResponse&gt; 或类似的东西。其中MoneyBoxWithdrawResponse 包含有关操作成功的信息,可能还有余额以及任何潜在的错误/异常详细信息。

【讨论】:

  • 同意测试优先的方法!我不敢相信我写了这么多未经测试的代码。 :|可怕的东西!你让我思考......我仍然不愿意将任何与 MoneyBox 无关的东西放在 MoneyBox 类中。如果在其他地方实现了相同的类,不同的系统,不同的平台,不同的消费代码等等等等。我在我的原始帖子中添加了一个替代解决方案,受您的启发但完全不同。也许将两者结合起来会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 2019-11-06
  • 2013-07-05
  • 2014-10-07
  • 2013-12-21
  • 2017-12-21
相关资源
最近更新 更多