TDD&;设计建议
本文关键字:amp TDD | 更新日期: 2023-09-27 18:28:19
我有一个方法,它调用Action<string>
public Action<string> DisplayError;
public void MyMethod()
{
DisplayError("ERROR");
}
在这个方法中,我想调用DisplayError,但我可以看到,如果DisplayError为null,它将抛出一个异常。
我可以运行一个测试来证明它会抛出异常。
所以我知道我想在我的代码中添加一个if (DisplayError != null)
,但我觉得这个设计在某种程度上是错误的。也许测试应该有所不同?
与其将Action作为公共字段,不如将其作为属性或传递到方法中。然后,您可以在这一点上进行null检查。我也怀疑你需要在设置后检索它,所以要么:
_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");
}
其中的第一个不需要消费者对代码进行任何更改。
当然,如果您只是与使用您的代码的团队合作,则根本不需要进行null检查。只要找出谁在错误地使用你的代码,并进行友好的聊天,找出误解所在。防御性编程不能很好地替代成员相互信任的团队,空检查也不如拥有一个定义明确、易于使用的界面有效。
你需要两个测试:
我的班级:
- 应该允许使用者处理任何错误
- 假设我将因任何原因产生错误(在此处设置上下文)
- 当我产生错误时(调用方法,让错误处理程序设置一些变量)
- 然后我应该将错误提供给处理程序(检查设置的变量)
- 应该确保附加了错误处理程序
- 假设我可能会产生错误(你可以在这里编写你喜欢的代码,因为它无关紧要)
- 当使用者在没有错误处理程序的情况下调用我时(使用null错误处理程序调用方法)
- 然后我应该立即要求消费者不要这样做(检查是否有异常)
它完全取决于上下文。
此类的用户是否需要根据合同设置值?然后它应该抛出一个异常。
它是可选的吗?那么你的检查是有效的,但如果你只是将DisplayError
默认为空Action,你会得到类似的行为
DisplayError = s => {};
您的方法还导致用户可以将DisplayError
设置为null
,在这种情况下,只有您才能决定什么是有效的。如果您将其设置为属性而不是字段,您将为自己提供更多选择。
_displayError = s => {};
public Action<string> DisplayError
{
get { return _displayError; }
set
{
_displayError = value ?? (s => {});
/* or throw on null */
}
}
我相信是在Steve Yeggie的一次演讲中,我听到了这一点:"虽然静态类型语言确实可以保护您在编译时免受一系列错误的影响,但它们并不能否定null检查的必要性。"
我觉得这很正常。
我只是在喝早上的咖啡,所以如果我完全错过了目标,请告诉我。