2010-08-06 115 views
0

我正在尝试单元测试自定义动作结果。我最近观看了Jimmy Bogard出色的MvcConf视频(“让你的控制器节食”)http://www.viddler.com/explore/mvcconf/videos/1/,并开始尝试并实施一些自定义操作结果。我已经管理了这个没有问题,ActionResult在运行时正常工作,但我无法尝试单元测试它们。如何对自定义动作进行单元测试结果

不幸的是,在代码下载中,没有针对Jimmy自定义操作方法的单元测试......这让我感到惊讶。

我意识到action方法只是返回ActionResult类型的实例和它实际调用ExecuteResult方法的MVC框架,这当然在运行单元测试时不可用。所以我的单元测试现在只是创建一个我自定义的ActionResult的实例,然后我调用ExecuteResult。

Unfortunatley在我自定义的ActionResult的ExecuteResult方法中,它也调用了我通过它的ViewResult的ExecuteResult方法。那时它爆炸了。我应该如何嘲笑/剔除这些东西才能让我的单元测试工作?

public class SendToAFriendActionResult : ActionResult 
{ 

    public const string INVALID_CAPTCHA = "You don't appear to have filled out the two words from the security image correctly to prove you're a human. Please try again."; 
    public const string INVALID_MODEL_STATE = "You don't appear to have filled out all the details correctly. Please try again."; 
    public const string CONTACT_FAIL = "Unfortunately we experiend a problem sending the link. Please try again later."; 
    public const string SEND_TO_A_FRIEND_FAIL_KEY = "ContactFail"; 

    private RedirectResult _success; 
    private ViewResult _failure; 
    private readonly SendToAFriendModel _model; 
    private readonly bool _captchaValid; 
    private readonly MessageBuilderServiceBase _mbs; 

    public RedirectResult Success 
    { 
     get { return _success; } 
     set { _success = value; } 
    } 

    public ViewResult Failure 
    { 
     get { return _failure; } 
     set { _failure = value; } 
    } 

    public SendToAFriendActionResult(RedirectResult success, ViewResult failure, SendToAFriendModel model, bool captchaValid, MessageBuilderServiceBase mbs) 
    { 
     _success = success; 
     _failure = failure; 
     _model = model; 
     _captchaValid = captchaValid; 
     _mbs = mbs; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 

     if (!_captchaValid) 
     { 
      Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = INVALID_CAPTCHA; 

      // On reaching this point I receive the error 
      // Object reference not set to an instance of an object 
      // as the MVC framework calls FindView 
      Failure.ExecuteResult(context); 
      return; 
     } 

     if (!context.Controller.ViewData.ModelState.IsValid) 
     { 
      Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = INVALID_MODEL_STATE; 
      Failure.ExecuteResult(context); 
      return; 
     } 

     _mbs.RecipientEmailAddress = _model.EmailRecipient; 
     _mbs.SendersName = _model.SendersName; 
     _mbs.Url = _model.URL; 
     var result = _mbs.sendMessage(); 

     if (!result) 
     { 
      Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = CONTACT_FAIL; 
      Failure.ExecuteResult(context); 
      return; 
     } 

     Success.ExecuteResult(context); 
    } 
} 

这里是我的单元测试的开始......

 IMessageService _emailMessageSerivce; 
     IGalleryRepository _repository; 

     var stfModel = new SendToAFriendModel 
     { 
      SendersName = "Someone", 
      URL = "http://someurl.com", 
      EmailRecipient = "[email protected]" 
     }; 

     var failure = new ViewResult() {ViewName ="SendToFriend"}; 
     const bool captchaValid = false; 
     var fakeControlllerContext = MockRepository.GenerateStub<ControllerContext>(null); 

     var stf = new SendToAFriendActionResult(null, failure, stfModel, captchaValid, null); 
     stf.ExecuteResult(fakeControlllerContext); 

我已经把意见SUT中显示为出现问题。

我知道我应该以某种方式存根/嘲弄,但我似乎无法解决此问题。

回答

0

ASP.NET MVC 2在行动(由麦博加德合着):

通过采取即难以测试代码实现的动作的 和将其放入 执行的方法一个行动结果, 你确保动作变得 明显更容易进行单元测试。 这是因为当您单元测试 操作时,您会断言操作返回的结果的类型 ,以及操作结果的状态 。 行动结果 的执行方法不作为单位 测试的一部分执行。

单元测试旨在隔离行为和问题。通过在您的自定义操作中调用ExecuteResult来混合您的疑虑。相反,我将有SendToAFriendActionResult返回实际的ActionResult(失败或成功):

public ActionResult GetAction(..) 
{ 
    ActionResult result; 
    //logic here to determine which ActionResult to return 
    return result; 
} 

在你的控制器:

public ViewResult SendToAFriend() 
    { 
     return SendToAFriendActionResult(null, failure, stfModel, captchaValid, null) 
      .GetAction(); 
    } 

此方法将允许MVC框架做的工作和隔离这些问题在您的自定义ActionResult之外。您的测试应该断言根据您设置的参数返回正确的动作,失败或成功类型。

+0

Thaks戴夫,这是非常有意义的。我从Jimmy的例子中看到了他所展示的MvcConf视频的代码,他实际上在最初的ActionResult的ExecuteMethod方法中调用了成功和失败ActionResults的ExecuteMethod。但是这个解决方案要好得多。它的一切都像魅力一样工作。实际上,我已经在行动书中获得了两个版本的MVC。也许我应该回去做更多的研究:) – 2010-08-06 18:12:12

+0

它*就这么发生了*,我今天正在阅读关于测试和自定义ActionResults的章节。情缘! – 2010-08-06 18:19:53

相关问题