2011-08-01 17 views
2

であるためのHttpContextのエラーを投げるのHttpContextのように:テスト私のコントローラは、私が呼んでコントローラーを持っている.NET MVC

public class AuthenticationService 
{ 
    private IPrincipal _user = HttpContext.Current.User; 

    ... 
} 

私のプロジェクトどこで:

[Authorize(Roles = "Administrador")] 
public class ApuradorController : Controller 
{ 
    private readonly Questiona2011Context _context = new Questiona2011Context(); 

    private readonly AuthenticationService _authenticationService = new AuthenticationService(); 
} 

のHttpContextはAuthenticationServiceクラスの呼び出しですコントローラーをインスタンス化するときにコントローラをテストします。エラーがスローされますprivate IPrincipal _user = HttpContext.Current.User;行:オブジェクト参照がオブジェクトのインスタンスに設定されていません。

コントローラーをテストするには何が必要ですか?

答えて

3

あなたが欠いている主なことは、テスト用にASP.NET MVCプロジェクトを設計する方法の知識です。

依存関係注入を使用するようにコントローラを設計する必要があります。つまり、コントローラはAuthenticationServiceの具体的な実装を使用するべきではなく、IAuthenticationServiceを使用して、具体的な実装が実行時に提供されるようにします。今のところ、コントローラが作成されると、AuthenticationServiceも作成されます。しかし、テストシナリオでは、HttpContextはnullであり、AuthenticationServiceの作成はNullReference例外で失敗しています。あなたがインターフェイス経由で設計した場合、テスト目的でAuthenticationServiceの偽実装をコントローラに提供し、例外をスローしません。

public interface IAuthenticationService 
{ 
    IPrincipal User {get;} 
} 

public class AuthenticationService : IAuthenticationService 
{ 
    private IPrincipal _user = HttpContext.Current.User; 

    ... 
} 

//the controller 
[Authorize(Roles = "Administrador")] 
public class ApuradorController : Controller 
{ 
    private readonly Questiona2011Context _context = new Questiona2011Context(); 

    private readonly IAuthenticationService _authenticationService; 

    public ApuradorController(IAuthenticationService authenticationService) 
    { 
     _authenticationService = authenticationService; 
    } 
} 

は、テストシナリオでは、たとえばmoqのために、偽のIAuthenticationServiceの実装のためのいくつかのモックライブラリを使用することができます。そして、それを嘲笑して価値を提供してください。

var mockAuthenticationService = new Mock<IAuthenticationService>(); 
//setup mockAuthenticationService 

var controller = new ApuradorController(mockAuthenticationService.Object); 

今回は、例外をスローしません。

ユニットテスト可能なプロジェクトデザインの原則を理解していない場合は、上記の情報は役に立ちません。クイックスタートについては、thisリンクをご覧ください。さらなる読書のためには、asp.net mvcに関するアドレス帳、私はそれらをスティーブン・サンダーソンによって推奨するでしょう。ユニットテスト可能なコントローラー設計の主な考え方は、コントローラー、偽のリポジトリー、サービスなどに偽のコンポーネントを供給し、ユニットテストされたコントローラーの一部だけを残すことができるということです。次に、これらの偽の部品とコントローラの反復をテストします。単体テストとは、その相互作用をテストすることを意味します。インタラクションが正しい場合、これらのコンポーネントの実際の実装では正しいでしょう。それらが間違っていれば、テストは失敗します。

+0

私はあなたの提案をしています:var authenticationService = new Mock (); varコントローラ=新しいApuradorController(authenticationService);しかし、私は例外を取得しています:引数型 'Moq.Mock は、パラメータ型' App.Services.IAuthenticationService 'に割り当てられません。 –

+0

新しいApuradorController(authenticationService.Object)を使用する必要があります。 ? –

+0

はい、あなたはそれを正確に行うべきです。また、そのモックApplicationServiceのUserプロパティを使用する場合は、Setup()を実行する必要があります。 moq documentation wikiのSetup()について読む - http://code.google.com/p/moq/wiki/QuickStart – archil

0

これを行うには、HttpContextBaseをモックする必要があります。 Hanselmanのarticleにそれが役立つかもしれません。

1

これは当然のことではありません。サービス層の依存関係をSystem.Web名前空間に追加しています。あなたのサービス層にユーザー名を渡す方が良いでしょう。おそらくコンストラクタ内にあり、基本サービスクラスのコンストラクタでそれを持つことをお勧めします。そのため、すべてのサービスメソッドでアクセス可能です。コントローラで

abstract class BaseService 
{ 
    procteced IPrinciple _userName; 

    public BaseService(IPrinciple userName) 
    { 
     _userName = userName; 
    } 
} 

class AuthenticationService : BaseService 
{ 
    public AuthenticationService(IPrinciple userName) 
     :base(userName) 
    { 

    } 
} 

:そのような可能性

AuthenticationService _service = new AuthenticationService(HttpContext.Current.User); 

- あなたはなどの役割のようなものにアクセスしようとしている場合、あなたはASP.netの周りに小さなラッパークラスを作成することが役に立つかもしれません役割/プロファイル情報へのアクセスなどの作業を行うために、サービスレイヤーからのインターフェースを実装するメンバーシップクラス。

0

あなたはのHttpContext(本物)をアップ配線し、それを使用することができます。

// Arrange 
    HttpContext.Current = 
    new HttpContext(
     new HttpRequest("", "http://tempuri.org", ""), 
     new HttpResponse(new StringWriter())); 
    HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("MyUser"), new[]{"Admin"}); 

    // Call your controller action... 

私は個人的に余分なマイルを行くと抽象化の別の層を追加し、STHを構築します。 IPrincipalAccessorのように、詳細については他のすべての回答を参照してください。

1

コントローラをユニットテストするためには、実際のHTTPを持っていないため、実行時にHTTPコンテキスト(要求、応答など)を置き換えることができるように、ユニットテスト時のコンテキスト。

もう1つ注意すべき点は、ユニットテスト(ApuradorController.Index())を使用してコントローラでアクションを呼び出すと、自動的にASP.NETと同じ実行パイプラインが取得されないことですMVCはランタイムを提供するため、「通常の」実行の一部であるイベントの一部はトリガーされません。たとえば、OnActionExecutingでいくつかのアクションを実行すると、ユニットテストでApuradorController.Index()を呼び出すときに、そのメソッドが自動的に起動されません。

テストコントローラは、プログラミング方法を変更する必要があるため、最初は難しい場合があります。正味の結果はよりよいコードですが、そこに行くのはちょっと難しいかもしれません。

関連する問題