我正在尝试找到从我的逻辑中解开消息框的最佳方法,以便我可以正确地对其进行单元测试。现在我想知道如果我只是创建了一个单独的帮助类(C#)就可以了,我可以稍后为我的消息框存根。例如:
static class messageBoxHelper
{
public static void msgBoxAlg(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icons, bool show)
{
if (show)
{
MessageBox.Show(message, title, buttons, icons);
}
}
然后,每当我需要使用消息框时,我只使用messageboxHelper / msgBoxAlg(...)而不是messagebox.show(...)。使用bool show我可以在测试期间启用或禁用它。
我只是想知道这是否是“正确的方法”。我的意思是,是否有更简单或更好的方法来做到这一点?我不能只丢弃消息框,他们将“重要”信息传递给用户(“你想关闭这个窗口吗?”是/否等)。它也可能只是我没有使用适当的软件工程,我应该将我的消息框与我的bussinesslogic分开更多?
是的,这是正确的方式。但是,您应该实现IDialogService
而不是静态类,并将其注入应该显示对话框的类中:
public interface IDialogService
{
void ShowMessageBox(...);
...
}
public class SomeClass
{
private IDialogService dialogService;
public SomeClass(IDialogService dialogService)
{
this.dialogService = dialogService;
}
public void SomeLogic()
{
...
if (ok)
{
this.dialogService.ShowMessageBox("SUCCESS", ...);
}
else
{
this.dialogService.ShowMessageBox("SHIT HAPPENS...", ...);
}
}
}
在测试SomeClass
期间,你应该注入IDialogService
的模拟对象而不是真实的。
如果您需要测试更多UI逻辑,请考虑使用MVVM模式。
查看控制反转(IoC),基本原则是执行操作的事物应该作为接口传递,然后使用IoC容器将接口绑定到应用程序的特定实现。为了在您的情况下轻松实现这一点,将作为接口的消息框的内容传递给您的单元测试创建该消息框服务的模拟(假)版本,该服务不显示消息框
看看http://martinfowler.com/articles/injection.html有关IoC的详细信息,我最喜欢的容器是Ninject(http://ninject.org)
理想情况下,您希望使用单元测试进行测试的代码是逻辑而不是UI。因此,您的测试逻辑不应该真正显示消息框。如果你想测试用户界面,那么我会建议Coded UI Tests。
从您的问题来看,我认为您的代码不应该真正使用MessageBox
。也许考虑使用回调或任意Action
,或Luke McGregor和Sergey V.提到的方法。
“单元测试”,其确切含义,是对原子行为的测试。这不是您可以为代码进行的唯一一种代码驱动的测试。特别是对于使用“是/否”对话框测试更长的场景,大规模代码驱动的测试通常比单元测试更有效。
但是为了能够更容易地编写它们,不仅可以创建Sergii提到的特殊服务,而且还可以使其调用异步:
public interface IDialogService
{
Task<bool> ShowYesNoMessageBox(...);
...
}
通过在非异步服务调用中包装消息框并模拟它们,对于更长的情况,您将通过在实际发生之前预测用户操作(做“安排”而不是“行动”)开始与“安排 - 行动 - 断言”模式相矛盾,这可能会导致测试中出现许多问题,特别是如果您的测试是使用BDD / SpecFlow完成的。使这些调用异步可以避免这些问题。有关详细信息和使用消息框进行大规模测试的示例,请参阅我的blog article。