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.

Géo
la source

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 );
Tvanfosson
la source
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);
0100110010101
la source
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.

Chandan Kumar
la source
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.");
    }
}
Xolartek
la source
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

Dinis Cruz
la source
Les liens sont rompus - veuillez inclure le code dans votre réponse
Hadès