Pergunta

Eu tenho um dispositivo de ensaio unidade em que eu estou tentando testar um ControllerAction em um controlador ASP.NET MVC que é usado para funções de pertinência em um aplicativo web. Eu estou tentando zombar do HttpContext para os testes. O ControllerAction em teste realmente define as propriedades do HttpContext, como valores de sessão, valores Response.Cookies, etc. Este não é todo o código, mas aqui está um exemplo áspero do teste que eu estou tentando obter a prazo :

[Test]
public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser()
{
    var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock};
    context.SetupAllProperties();
    var provider = new Mock<MembershipProvider>(new object[] {context.Object});
    var controller = new AccountController(context.Object, provider.Object);
    // This just sets up a local FormCollection object with valid user data 
    // in it to use to attempt the registration
    InitializeValidFormData();
    ActionResult result = controller.Register(_registrationData);
    Assert.IsInstanceOfType(typeof(ViewResult), result);
    // Here is where I'd like to attempt to do Assertions against properties 
    // of the HttpContext, like ensuring that a Session object called "User" 
    // exists, and new auth cookie exists on the Response.Cookies collection. 
    // So far I've been unable to successfully check the values of those properties.
    // I've been unsuccessful in getting those properties setup correctly on my 
    // mock object so that my ControllerAction can actually *set* their values, 
    // and that I can make assertions on them afterwards. The above code actually
    // generates a StackOverflowException (which I've reported) on the
    // context.SetupAllProperties() call. What am I doing wrong, or what do I need 
    // to do to be able to set and assert on those context properties?
}

Não sei o que estou fazendo de errado, mas eu adoraria se alguém poderia me aponte na direção certa e me mostrar como configurar esta simulada HttpContextBase objeto, valores que meu controlador pode realmente definir em suas propriedades, e Eu posso fazer afirmações sobre essas propriedades para garantir que a minha ControllerAction está fazendo o que eu preciso que ele.

Am I esta aproximando o caminho errado? Eu sei que os controladores MVC ter um ControllerContext que eu possa usar para valores para Session, etc, mas eu não consigo descobrir como algo assim poderia ser ridicularizado sem injetá-lo. Existe alguma maneira de fazer isso em vez disso? (Eu também preciso ser capaz de passar o contexto em que a minha MembershipProvider também) isso seria uma abordagem melhor?

Graças.

Foi útil?

Solução

Eu estou usando uma versão de algum código Steve Sanderson incluiu em sua Pro Asp.NET MVC livro ... e eu estou tendo atualmente um dilema moral se não há problema em postar o código aqui. Que tal eu compromisso com uma versão altamente simplificada? ;)

Então, isso pode ser facilmente reutilizados, criar uma classe semelhante ao abaixo que você vai passar o seu controlador. Isto irá configurar suas simulações e configurá-los para ControllerContext do seu controlador

public class ContextMocks
{
    public Moq.Mock<HttpContextBase> HttpContext { get; set; }
    public Moq.Mock<HttpRequestBase> Request { get; set; }
    public RouteData RouteData { get; set; }

    public ContextMocks(Controller controller)
    {
        //define context objects
        HttpContext = new Moq.Mock<HttpContextBase>();
        HttpContext.Setup(x => x.Request).Returns(Request.Object);
        //you would setup Response, Session, etc similarly with either mocks or fakes

        //apply context to controller
        RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
        controller.ControllerContext = new ControllerContext(rc, controller);
    }
}

E, em seguida, no seu método de teste que você tinha acabado de criar uma instância de ContextMocks e passar o objeto controlador que você está testando:

[Test]
Public void test()
{
     var mocks = new ContextMocks(controller);
     var req = controller.Request; 
     //do some asserts on Request object
}

Parece muito semelhante a exemplos de Craig, mas isso é com Moq v3. Eu tenho que dar adereços para Steve Sanderson para isso - eu estou usando isso como uma base para testar todos os tipos de outro modo tradicionalmente difícil de teste de material: cookies, sessão, pedido método, querystring e mais

Outras dicas

Aqui está como eu fazê-lo .

    public static HttpContextBase FakeHttpContext()
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var user = new Mock<IPrincipal>();
        var identity = new Mock<IIdentity>();

        request.Expect(req => req.ApplicationPath).Returns("~/");
        request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
        request.Expect(req => req.PathInfo).Returns(string.Empty);
        response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>()))
            .Returns((string virtualPath) => virtualPath);
        user.Expect(usr => usr.Identity).Returns(identity.Object);
        identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true);

        context.Expect(ctx => ctx.Request).Returns(request.Object);
        context.Expect(ctx => ctx.Response).Returns(response.Object);
        context.Expect(ctx => ctx.Session).Returns(session.Object);
        context.Expect(ctx => ctx.Server).Returns(server.Object);
        context.Expect(ctx => ctx.User).Returns(user.Object);

        return context.Object;
    }

Esta é uma versão melhorada do a biblioteca MvcMockHelpers lançado pela Scott Hanselman . Este é Moq código 2.0; a sintaxe é ligeiramente diferente em 3.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top