カスタム アクションの結果を単体テストしようとしています。私は最近、Jimmy Bogard の優れた MvcConf ビデオ ("put your controllers on a Diet") http://www.viddler.com/explore/mvcconf/videos/1/を見て、いくつかのカスタム アクション結果を試して実装し始めました。問題なく実行できましたが、ActionResult は実行時に正常に動作しますが、単体テストを実行しようとすると問題が発生します。
残念ながら、コードのダウンロードには、Jimmy のカスタム アクション メソッドの単体テストがありません。
アクション メソッドは単に ActionResult 型のインスタンスを返すだけであり、その MVC フレームワークは ExecuteResult メソッドを実際に呼び出しますが、これはもちろん、単体テストの実行時には使用できません。したがって、単体テストはカスタム ActionResult のインスタンスを作成するだけであり、その後 ExecuteResult を呼び出します。
残念ながら、カスタム 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 = "a-friend@somewherelse.com"
};
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 にコメントを入れました。
どうにかしてスタブ/モックを作成する必要があることはわかっていますが、これを解決できないようです。