TDD&设计咨询

时间:2012-03-19 15:08:08

标签: c# .net unit-testing tdd

我有一个调用Action<string>

的方法
public Action<string> DisplayError;

public void MyMethod()
{
  DisplayError("ERROR");
}

在这个方法中我想调用DisplayError但是我可以看到,如果DisplayError为null,它将抛出异常。

我可以运行一个测试,证明它会抛出异常。

所以我知道我想在我的代码中添加if (DisplayError != null),但我觉得这个设计在某种程度上是错误的。也许测试应该有所不同?

3 个答案:

答案 0 :(得分:1)

这完全取决于背景。

此类的用户是否需要根据合约设置值?然后它应该抛出异常。

可选吗?那么你的检查是有效的,但是如果你只是将DisplayError默认为一个空的Action,你会得到类似的行为

DisplayError = s => {};

您的方法还可能会导致用户 DisplayError设置为null,在这种情况下,只有您可以决定什么是有效的。如果您将其设置为属性而不是字段,您将为自己提供更多选项。

_displayError = s => {};

public Action<string> DisplayError
{
   get { return _displayError; }
   set 
   { 
       _displayError = value ?? (s => {}); 
       /* or throw on null */
   }
}

答案 1 :(得分:1)

不要将Action设为公共字段,而是将其设为属性或将其传递给方法。然后,您可以在该点进行空检查。我也怀疑你需要在设置之后检索它,所以:

_displayError = (s) => { throw new ArgumentNullException("Please tell me what to do with this exception!"); };

public Action<string> DisplayError
{
    set 
    {
        if (value == null) { throw new ArgumentNullException("I need this!"); }
        _displayError = value;
    }
}

public void MyMethod()
{
    _displayError("ERROR");
}

或者:

public void MyMethod(Action<string> displayError)
{
    if (displayError == null) { throw new ArgumentNullException("I need this!"); }
    displayError("ERROR");
}

其中第一个不应要求消费者更改代码。

当然,如果您只是与使用代码的团队合作,那么根本不需要进行空检查。只需找出谁错误地使用您的代码并进行友好聊天,以找出误解的位置。防御性编程不是一个很好的替代成员相互信任的团队,而且无效检查不如拥有明确定义,易于使用的界面那么有效。

您需要进行2次测试:

我的课程:

  • 应该允许消费者处理任何错误
    • 鉴于我将因任何原因(在此设置上下文)产生错误
    • 当我产生错误时(调用方法,让错误处理程序设置一些变量)
    • 然后我应该将错误提供给处理程序(检查已设置的变量)
  • 应确保附加错误处理程序
    • 鉴于我可能会产生错误(您可以在此处编写您喜欢的内容,因为它无关紧要)
    • 当消费者在没有错误处理程序的情况下调用我时(使用空错误处理程序调用该方法)
    • 然后我应该立即要求消费者不要这样做(检查例外情况)

答案 2 :(得分:0)

我相信在Steve Yeggie的一次谈话中,我听到了这一点:有些东西可以说'虽然静态类型的语言在编译时确实可以保护你免受各种错误的影响,但它们并没有否定空检查'。

我觉得这很正常。

我只是在喝早晨的咖啡,所以如果我完全错过了这个标记,请告诉我。