2017-01-17 4 views
0

При запуске моего модульного метода тестирования я получаю ошибку FormsAuthentication.SignOut(). Я дразнил HttpContext как этотОшибка сбрасывания в модульном тесте 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; 

в методе входа

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. 
} 

А и тест примера

Примечание: Я использую Moq для издевательских зависимостей и FluentAssertions для утверждения результатов.

[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); 
} 
Смежные вопросы