Comment se moquer du HttpContext dans ASP.NET MVC à l'aide de Moq?


101
[TestMethod]
public void Home_Message_Display_Unknown_User_when_coockie_does_not_exist()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    context
        .Setup(c => c.Request)
        .Returns(request.Object);
    HomeController controller = new HomeController();

    controller.HttpContext = context; //Here I am getting an error (read only).
    ...
 }

mon contrôleur de base a un remplacement de l'initialisation qui obtient ce requestContext. J'essaie de transmettre cela, mais je ne fais pas quelque chose de bien.

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);
}

Où puis-je obtenir plus d'informations sur la simulation de mon RequestContext et de HttpContext à l'aide de Moq? J'essaye de me moquer des cookies et du contexte général.

Réponses:


61

HttpContext est en lecture seule, mais il est en fait dérivé de ControllerContext, que vous pouvez définir.

 controller.ControllerContext = new ControllerContext( context.Object, new RouteData(), controller );

Celui-ci a fonctionné pour moi en me permettant de définir un HttpContext simulé sur le contrôleur.
Joel Malone

39

Créez une requête, une réponse et placez-les toutes les deux dans HttpContext:

HttpRequest httpRequest = new HttpRequest("", "http://mySomething/", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);

La question concerne les * classes de base, c'est-à-dire HttpRequestBase, pas HttpRequest - je ne sais pas pourquoi les deux sont nécessaires moi-même et encore plus ennuyeux qu'elles soient "scellées". Aucun moyen de définir LogonUserIdentity :(
Chris Kimpton

S'ils ont rassemblé ma référence, c'est toujours possible via la communication à distance, donc cela ne devrait pas être un problème.
0100110010101

1
@ChrisKimpton: En dernier recours, il y a toujours de la réflexion ;-)
Oliver

Cela fonctionne lorsque vous l'attachez au contrôleur, comme ceci: controller.ControllerContext = new ControllerContext (new HttpContextWrapper (httpContextMock), new RouteData (), controller);
Andreas Vendel

Oui. vous pouvez en effet définir .LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus

12

Merci utilisateur 0100110010101.

Cela a fonctionné pour moi et j'ai eu un problème lors de l'écriture du testcase pour le code ci-dessous:

 var currentUrl = Request.Url.AbsoluteUri;

Et voici les lignes qui ont résolu le problème

HomeController controller = new HomeController();
//Mock Request.Url.AbsoluteUri 
HttpRequest httpRequest = new HttpRequest("", "http://mySomething", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);
controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock), new RouteData(), controller);

Cela pourrait être utile pour les autres.


Je n'arrive pas à utiliser le type HttpRequest - est-ce autre chose maintenant?
Vincent Buscarello du

1
Ce n'est pas utile car tous les champs de HttpRequest sont immuables
A br

5

Voici comment j'ai utilisé ControllerContext pour passer un faux chemin d'application:

[TestClass]
public class ClassTest
{
    private Mock<ControllerContext> mockControllerContext;
    private HomeController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        mockControllerContext = new Mock<ControllerContext>();
        sut = new HomeController();
    }
    [TestCleanup]
    public void TestCleanup()
    {
        sut.Dispose();
        mockControllerContext = null;
    }
    [TestMethod]
    public void Index_Should_Return_Default_View()
    {

        // Expectations
        mockControllerContext.SetupGet(x => x.HttpContext.Request.ApplicationPath)
            .Returns("/foo.com");
        sut.ControllerContext = mockControllerContext.Object;

        // Act
        var failure = sut.Index();

        // Assert
        Assert.IsInstanceOfType(failure, typeof(ViewResult), "Index() did not return expected ViewResult.");
    }
}

1
Pourquoi avez-vous besoin de passer un faux chemin d'application?
the_law

Le code MVC l'exécutera et lèvera une exception null s'il n'y est pas.
Joshua Ramirez

5

Voici un exemple de la façon dont vous pouvez configurer cela: Mocking HttpContext HttpRequest and HttpResponse for UnitTests (using Moq)

Notez les méthodes d'extension qui aident vraiment à simplifier l'utilisation de ces classes moqueuses:

var mockHttpContext = new API_Moq_HttpContext();

var httpContext = mockHttpContext.httpContext();

httpContext.request_Write("<html><body>".line()); 
httpContext.request_Write("   this is a web page".line());  
httpContext.request_Write("</body></html>"); 

return httpContext.request_Read();

Voici un exemple de la façon d'écrire un test unitaire à l'aide de moq pour vérifier qu'un HttpModule fonctionne comme prévu: Test unitaire pour HttpModule utilisant Moq pour envelopper HttpRequest

Mise à jour: cette API a été refactorisée en


Les liens sont rompus - veuillez inclure le code dans votre réponse
Hadès
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.