0

カスタム アクションの結果を単体テストしようとしています。私は最近、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 にコメントを入れました。

どうにかしてスタブ/モックを作成する必要があることはわかっていますが、これを解決できないようです。

4

1 に答える 1

0

ASP.NET MVC 2 In Action (Jimmy Bogard 共著)から:

テストが難しいコードをアクションから取り出してアクション結果の Execute メソッドに入れることで、アクションの単体テストが大幅に容易になります。これは、アクションを単体テストするときに、アクションが返すアクション結果のタイプとアクション結果の状態をアサートするためです。アクション結果の Execute メソッドは、単体テストの一部として実行されません。

単体テストは、動作と懸念事項を分離するように設計されています。カスタム アクション内から 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 の外部にある問題を分離できます。テストでは、設定したパラメーターに基づいて、正しいタイプのアクション (失敗または成功) が返されることをアサートする必要があります。

于 2010-08-06T16:59:45.683 に答える