2013-10-04 63 views
1

我正在寻找关于Arrange/Act/Assert的一些澄清,我在开发过程中将其作为Given-When-Then实现。我试图坚持这个概念,但我发现在某些事件(尤其是用户输入)期间,我必须重新考虑一个“Act”动作作为“Arrange”动作,以便在单元测试中正确捕获。我在这里使用Moq作为我的模拟框架。Given-When-Then当处理用户输入

例如:在我的项目中,代码的焦点是用户提供的图像。用户可以选择图像的功能存在,但是如果图像已经存在,它将询问用户是否要替换活动图像,或取消操作并保留活动图像。我觉得写此特定情形的适当的办法是:

鉴于与已经存在的图像的工作空间
用户请求一个新的形象
用户选择更换活动图像
然后程序应更换图像

Testwise,它看起来事端摹这样的:

mockModel.SetupProperty(m => m.Image, new Bitmap(100, 100)); // Given 
mockView.Raise(v => v.UserRequestsNewImage += null);   // When 
mockMBox.Setup(mb => mb.ViewResult).Returns(ViewResult.OK); // And 
mockView.Verify(v => v.OpenAddImageFileDialog(), Times.Once); // Then 

Codewise,在我的演讲,它看起来是这样的:

private void view_UserRequestsNewImage() 
{ 
    if (model.Image != null) 
    { 
    mbox.ShowDialog(); 

    if (mbox.ViewResult == ViewResult.Cancel) 
     return; 
    } 

    view.OpenAddImageFileDialog(); 
} 

但这种失败,因为消息框的Setup视图的Raise被调用后发生。因此,我需要它(并使用Setup使得它感觉像一个“排列”设置反正)前移动Setup

鉴于与已经存在的图像的工作空间
用户选择更换活动图像
用户请求一个新的形象
然后程序应更换图像

但是现在,我的情景感觉不合适,而且流程不正确。我觉得用户选择替换图像(Setup),因为它出现用户选择添加一个新图像(Raise),应该是Act步骤的一部分,但为了让它正确地模拟,我需要把它放在编配步骤中。

我在这里使用嘲笑框架错误吗?有一个更好的方法吗?或者我是不是很现实地烦恼用户输入步骤应该位于Given-When-Then设置中的位置?

在此先感谢。

+0

有了一些自定义的扩展方法,您可以链接在一起的时候,而且是如此你写他们,因为他们流逻辑,但不是直接调用起订量,把拉姆达在一个堆栈和终止表达后,按相反​​的顺序执行。 –

回答

1

“当用户请求一个新形象”用户选择替换当前图像。

所以你可以重新写的“给定,那么,什么时候”阅读:

  • 鉴于与已经存在的图像的工作空间
  • 用户选择更换活跃图像
  • 然后程序应更换图像

即省略“当”,规定替换当前图像时的“用户请求一个新的图像”,因为它们必须以这个反正。

而且我会沟评论(代码异味,但理所当然不会有太多的人!),并把这些测试步骤分成小的方法,像这样:

void GivenImageAlreadyPresent() 
{ 
mockModel.SetupProperty(m => m.Image, new Bitmap(100, 100)); 
} 

void WhenActiveImageReplaced() 
{ 
mockMBox.Setup(mb => mb.ViewResult).Returns(ViewResult.OK); 
mockView.Raise(v => v.UserRequestsNewImage += null);   
} 

void ThenImageShouldBeReplaced() 
{ 
mockView.Verify(v => v.OpenAddImageFileDialog(), Times.Once); 
} 

void Test() 
{ 
GivenImageAlreadyPresent(); 
WhenActiveImageReplaced(); 
ThenImageShouldBeReplaced(); 
} 

这使得实际测试读更好(即现在自行记录),并且如果需要的话,它可以重新使用这些步骤。

+0

嗯,这是一个相当简单的,直接的,“为什么-didn't-I-思的,即”一种解决方案。谢谢。词选择使所有区别!并且为了记录 - 我已经完全按照您的方式进行了操作(将操作置于方法中),但我只是想简单地说明我的问题。我最初尝试使用SpecFlow的BDD,但它并没有我流所以我决定只是处理所有的方法手动这样的,我觉得它工作得很好。再次感谢! – Arclight

+0

@Arclight很高兴我能帮忙:) –