2016-07-22 10 views
1

すべてのコントローラが派生したBaseControllerがあり、ViewBagに値(ユーザーのニックネーム)が設定されています。私はこれを行って、すべてのコントローラに対して暗黙的に設定することなくレイアウトの値にアクセスできるようにしています(これを行うより良い方法を提案すれば、進んでください!)。MVC 5コントローラのOWINContextを模擬する方法

public class BaseController : Controller 
{ 
    public BaseController() 
    { 
     InitialiseViewBag(); 
    } 

    protected void InitialiseViewBag() 
    { 
     ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId()); 

     ViewBag.NickName = user?.NickName; 
    } 
} 

私はその後にHomeControllerに、例えば、そのクラスを派生:私は来て(ないここに示されている別のビューで使用されるリポジトリ、)私のコントローラの他の依存関係を設定した

public class HomeController : BaseController 
{ 
    private readonly IRoundRepository _repository = null; 

    public HomeController(IRoundRepository repository) 
    { 
     _repository = repository; 
    } 

    public ActionResult Index() 
    { 
     return View(); 
    } 
} 

コンストラクタを使用して、DI用のStructureMapを使用しています。ニックネームを取得するためにBaseControllerの行を削除すると、すべてうまく動作します。私はOWINコンテキストを使用してニックネームを取得するには、その行を含む場合

問題は、私のテストはこれで失敗し

のSystem.InvalidOperationException:ノーowin.Environmentアイテムがコンテキストで を発見されました。

これが今のように私のテストで:

[TestMethod] 
public void HomeControllerSelectedIndexView() 
{ 
    // Arrange 
    HttpContext.Current = _context; 
    var mockRoundRepo = new Mock<IRoundRepository>(); 
    HomeController controller = new HomeController(mockRoundRepo.Object); 

    // Act 
    ViewResult result = controller.Index() as ViewResult; 

    // Assert 
    Assert.IsNotNull(result); 
} 

私はそれが働いていない、なぜ私は理解してだと思うが、私はそれを回避する方法を考え出すことはできません。

私のテスト中にユーザの身元にアクセスして転倒しないように、このベースコントローラを偽装する/注入する/そうでなければセットアップする必要がありますか?

注:私は依存性注入を使うのがとても新しいので、明らかに何か、あるいはこれについて完全に間違っている、または重要な情報を残していると、私は驚かないでしょう!

+1

あなたの現在のデザインは、テストするのが非常に簡単ではないコンポーネントに強く結びついています。主に 'HttpContext'です。ユーザーを認証するときに、ユーザープリンシパル上の要求としてニックネームを関連付ける方がよいでしょう。そうすれば、あなたのコントローラーはそれを得る方法の詳細に関心を持つ必要はありません。また、ユーザープリンシパルにアクセスするだけで、ビュー内でアクセスできます。デフォルトのプロジェクトテンプレートを使用している場合は、サインイン時にAccountControllerでニックネームクレームを設定することができます。 – Nkosi

+0

ありがとう、代わりにクレームを使用します。ここでは、テスト可能性の問題を避けるために、できる場合はHttpContextまたはOWINContextでANYTHINGを使用しないでください。 –

+0

そうではありません。私はテストするコードがうまく設計されているかどうかの指標であることをテストするのがいかに簡単かを言います。ソリッドと考える。 – Nkosi

答えて

1

Nkosiの提案のおかげで、これを解決しました。

私は自分のアイデンティティに主張を追加私の ApplicationUser.GenerateUserIdentityAsync()方法で

:私の意見では今

public static class IdentityExtensions 
{ 
    public static string GetNickName(this IIdentity identity) 
    { 
     var claim = ((ClaimsIdentity)identity).FindFirst("NickName"); 

     // Test for null to avoid issues during local testing 
     return (claim != null) ? claim.Value : string.Empty; 
    } 
} 

:私はIdentityオブジェクトのNickName請求にアクセスするためのヘルパー拡張メソッドを追加

userIdentity.AddClaim(new Claim("NickName", this.NickName)); 

(またはコントローラ)私はクレームに直接アクセスすることができます。例えば、

<span class="nickname">@User.Identity.GetNickName()</span> 
関連する問題