2017-01-17 7 views
0

ユニットテストメソッドを実行しているときにFormsAuthentication.SignOut()エラーが発生しています。私は、loginメソッドでこのユニットテストでの投げエラーFormsAuthentication.SignOut()

var httpRequest = new HttpRequest("", "http://localhost/", ""); 
var stringWriter = new StringWriter(); 
var httpResponse = new HttpResponse(stringWriter); 
var httpContext = new HttpContext(httpRequest, httpResponse); 
var sessionContainer = new HttpSessionStateContainer(
    "id", 
    new SessionStateItemCollection(), 
    new HttpStaticObjectsCollection(), 
    10, 
    true, 
    HttpCookieMode.AutoDetect, 
    SessionStateMode.InProc, 
    false); 
SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer); 
var controller = new AccountController(); 
var requestContext = new RequestContext(new HttpContextWrapper(httpContext), new RouteData()); 
controller.ControllerContext = new ControllerContext(requestContext, controller); 
var actual = controller.Login(new CutomerModel() { Login = "admin", Password = "Password1" }); 
return httpContext; 

のようにHttpContextを嘲笑している

public ActionResult Login(CutomerModel obj) 
{ 
    FormsAuthentication.SignOut(); 
} 

FormsAuthentication.SignOut();

「オブジェクト参照がオブジェクトのインスタンスに設定されていませんがスローされます。 '

答えて

1

静的メソッドFormsAuthentication.SignOutは、ユニットテスト中に使用できません別の静的メンバHttpContext.Current、に依存しています。静的なHttpContext.Currentにコントローラをしっかりと結合すると、テストするのが非常に難しいコードになります。静的呼び出しに結合しないようにしてください。

サイドノート:コードの単体テストを設定することが困難であることは、レビューしてリファクタリングする必要があるという確かな兆候です。

要約FormsAuthenticationは、自分の懸念事項/インターフェイスを呼び出して、それらを嘲笑することができます。

public interface IFormsAuthenticationService { 

    void SignOut(); 

    //...other code removed for brevity 
} 

実際の呼び出しをラップすると、実際にはHttpContext.Currentが有効になるはずです。 DIコンテナが依存関係を解決する方法を認識していることを確認してください。

public class FormsAuthenticationService : IFormsAuthenticationService { 

    public void SignOut() { 
     FormsAuthentication.SignOut(); 
    } 

    //...other code removed for brevity 

} 

コントローラーをリファクタリングするには、抽象化に依存して実装上の問題がないようにする必要があります。

public class AccountController : Controller { 

    //...other code removed for brevity. 

    private readonly IFormsAuthenticationService formsAuthentication; 

    public AccountController(IFormsAuthenticationService formsAuthentication) { 
     //...other arguments removed for brevity 
     this.formsAuthentication = formsAuthentication; 
    } 

    public ActionResult Login(CutomerModel obj) { 
     formsAuthentication.SignOut(); 
     //... 
     return View(); 
    } 

    //...other code removed for brevity. 
} 

とし、例えば、テスト

注:私は結果を主張するためにモックの依存関係のためMoqFluentAssertionsを使用しています。

[TestMethod] 
public void LoginTest() { 
    //Arrange 
    var model = new CutomerModel() { Login = "admin", Password = "Password1" };   
    var mockFormsAuthentication = new Mock<IFormsAuthenticationService>(); 

    var controller = new AccountController(mockFormsAuthentication.Object); 

    //Act 
    var actual = controller.Login(model) as ViewResult; 

    //Assert (using FluentAssertions) 
    actual.Should().NotBeNull(because: "the actual result should have the returned view"); 
    mockFormsAuthentication.Verify(m => m.SignOut(), Times.Once); 
} 
関連する問題