2

データを ViewData に詰め込むコントローラーを単体テストしようとしています。私たちのすべてのビューには、同様のデータ (URL から派生した顧客情報) が必要です。そのため、元の開発者は、呼び出しをすべてのコントローラー メソッドに配置する代わりに、この ViewData スタッフィングを OnActionExecuting イベントに配置することを選択しました。

もちろん、単体テストからコントローラーのアクションを呼び出すと、OnActionExecuting は起動しません。(ありがとうMVCチーム!)

そこで、カスタム ビュー エンジンを作成し、ビューが要求されたときに顧客データを controllerContext に詰め込んでみました。これはブラウザーでは問題なく動作しますが、このテストを実行すると、viewEngine は無視されます。ViewEngines.Add(new funkyViewEngine) の量は効果がありません。

  [TestMethod()]
            public void LoginTest()
            {
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(new FunkyViewEngine());

                UserController target = new UserController();
                target.SetStructureMap();  <--sets us to use the test repo

                target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com");  <--moq magic
                var actual = target.Login();
                Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
                var  vr = actual as ViewResult;
                Assert.IsTrue(vr.ViewData.Community() != null);  <--"Community" should be set by viewengine
                Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
                Assert.IsTrue(vr.ViewData.Community().CanRegister);
            }

ここに希望はありますか?1)ブラウザーとユニットフレームワークの両方でコントローラーの実行時に呼び出されるメソッドを作成するか、2)ユニットフレームワークを取得してビューエンジンを呼び出すにはどうすればよいですか。

4

2 に答える 2

2

ご迷惑をおかけして申し訳ありません。OnActionExecuting単体テストからアクション メソッドを直接呼び出したときに呼び出されていないのは、MVC での動作がそうではないためです。

リクエストは「パイプライン」を介して実行されます。これは、この領域に関する限り、ControllerActionInvoker. このクラスは以下を担当します。

  1. アクションメソッドを見つける
  2. アクション フィルターのOnActionExecutingメソッドの呼び出し (注:コントローラー クラスもアクション フィルターです)
  3. アクションメソッド自体を呼び出す
  4. アクション フィルターのOnActionExecutedメソッドの呼び出し
  5. 結果の処理 (例: ビューの検索とレンダリング)

単体テストでは、ステップ 3. を直接呼び出し、他のすべてのステップをスキップしています。単体テストでは、アクションが機能するために必要なセットアップ コードを呼び出すのは、ユーザーの責任です。

ControllerActionInvokerただし、これは、 を使用してパイプライン全体を実行する単体テストを作成する必要があるという意味ではありません。私たち (MVC チーム) は、すべての部分が連携して動作することを既に確認しています。

代わりに、特定のアプリケーション コードをテストする必要があります。この場合、次の単体テストを行うことを検討してください。

  1. コントローラーで特定の Url 呼び出しOnActionExecutingが正しい Customer オブジェクトを ViewData に入れることを確認するテスト
  2. ViewData に存在する Customer オブジェクトを指定して、アクション メソッドが適切な結果を返すことを確認するテスト

最後のポイントは、機能を に保持する必要があるということですOnActionExecuting。カスタム ビュー エンジンは、明らかに不適切な場所です。

于 2010-12-10T18:21:03.867 に答える
0

おそらくあなたが探している答えではありませんが、カスタムMvcHandlerを使用して同じ目標を達成しています (マルチテナント アプリで URL から顧客を取得する)。ViewEngine は、この種のロジックには適していないように思えます...

私のカスタム ハンドラーは多かれ少なかれ次のようになります。

public class AccountMvcHandler : MvcHandler
{
    public Account Account { get; private set; }

    protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
    {
        return base.BeginProcessRequest(httpContext, callback, state);
    }

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        string accountName = this.RequestContext.RouteData.GetRequiredString("account");
        Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName);

        return base.BeginProcessRequest(httpContext, callback, state);
    }
}
于 2010-12-10T17:21:23.237 に答える