Comment se moquer de la demande sur le contrôleur dans ASP.Net MVC?


171

J'ai un contrôleur en C # utilisant le framework ASP.Net MVC

public class HomeController:Controller{
  public ActionResult Index()
    {
      if (Request.IsAjaxRequest())
        { 
          //do some ajaxy stuff
        }
      return View("Index");
    }
}

J'ai eu quelques conseils sur la moquerie et j'espérais tester le code avec ce qui suit et RhinoMocks

var mocks = new MockRepository();
var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);

var controller = new HomeController();
controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);

Cependant, je continue à recevoir cette erreur:

Exception System.ArgumentNullException: System.ArgumentNullException: la valeur ne peut pas être nulle. Nom du paramètre: requête à System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest (requête HttpRequestBase)

Puisque l' Requestobjet sur le contrôleur n'a pas de setter. J'ai essayé de faire fonctionner correctement ce test en utilisant le code recommandé à partir d'une réponse ci-dessous.

Cela a utilisé Moq au lieu de RhinoMocks, et en utilisant Moq, j'utilise ce qui suit pour le même test:

var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers["X-Requested-With"]).Returns("XMLHttpRequest");

var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new HomeController(Repository, LoginInfoProvider);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);

mais obtenez l'erreur suivante:

Exception System.ArgumentException: System.ArgumentException: configuration non valide sur un membre non remplaçable: x => x.Headers ["X-Requested-With"] à Moq.Mock.ThrowIfCantOverride (configuration de l'expression, MethodInfo methodInfo)

Encore une fois, il semble que je ne puisse pas définir l'en-tête de la demande. Comment définir cette valeur dans RhinoMocks ou Moq?


Remplacez Request.IsAjaxRequest par Request.IsAjaxRequest ()
eu-ge-ne

Mock Request.Headers ["X-Requested-With"] ou Request ["X-Requested-With"] au lieu de Request.IsAjaxRequest (). J'ai mis à jour ma question
eu-ge-ne

Réponses:


212

Utilisation de Moq :

var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers).Returns(
    new System.Net.WebHeaderCollection {
        {"X-Requested-With", "XMLHttpRequest"}
    });

var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);

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

ACTUALISÉ:

Mock Request.Headers["X-Requested-With"]ou Request["X-Requested-With"]au lieu de Request.IsAjaxRequest().


1
Je reçois le message "L'argument Type pour la méthode 'ISetupGetter <T, TProperty> Moq.Mock <T> .SetupGet <Tpropert> .... ne peut pas être déduit de uage. Essayez de spécifier les arguments de type explicitement. Quel type dois-je définir 'var request =' à bien pour que cela fonctionne?
Nissan

Je viens de mettre à jour ma réponse - pas Request.IsAjaxRequest mais Request.IsAjaxRequest (). Mettez également à jour votre question
eu-ge-ne

Génère toujours: Exception System.ArgumentException: System.ArgumentException: Configuration non valide sur un membre non remplaçable: x => x.IsAjaxRequest () à Moq.Mock.ThrowIfCantOverride (Configuration de l'expression, MethodInfo methodInfo)
Nissan

Le problème est que IsAjaxRequest () est une méthode d'extension statique et ne peut pas être moquée - j'ai mis à jour ma réponse.
eu-ge-ne

doit être context.SetupGet (x => x.Request) .Returns (request.Object); votre code ci-dessus manque toujours le 's' au retour entraîne toujours une exception System.ArgumentException: System.ArgumentException: configuration non valide sur un membre non remplaçable: x => x.Headers ["X-Requested-With"] chez Moq Message d'erreur .Mock.ThrowIfCantOverride (Configuration de l'expression, MethodInfo methodInfo)
Nissan

17

Pour toute personne utilisant NSubstitute, j'ai pu modifier les réponses ci-dessus et faire quelque chose comme ça ... (où Details est le nom de la méthode Action sur le contrôleur)

 var fakeRequest = Substitute.For<HttpRequestBase>();
        var fakeContext = Substitute.For<HttpContextBase>();
        fakeRequest.Headers.Returns(new WebHeaderCollection { {"X-Requested-With", "XMLHttpRequest"}});
        fakeContext.Request.Returns(fakeRequest);
        controller.ControllerContext = new ControllerContext(fakeContext, new RouteData(), controller);
        var model = new EntityTypeMaintenanceModel();

        var result = controller.Details(model) as PartialViewResult;

        Assert.IsNotNull(result);
        Assert.AreEqual("EntityType", result.ViewName);

13

Voici une solution de travail utilisant RhinoMocks. Je l'ai basé sur une solution Moq que j'ai trouvée sur http://thegrayzone.co.uk/blog/2010/03/mocking-request-isajaxrequest/

public static void MakeAjaxRequest(this Controller controller)
{
        MockRepository mocks = new MockRepository();

        // Create mocks
        var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
        var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();

        // Set headers to pretend it's an Ajax request
        SetupResult.For(mockedHttpRequest.Headers)
            .Return(new WebHeaderCollection() {
                {"X-Requested-With", "XMLHttpRequest"}
            });

        // Tell the mocked context to return the mocked request
        SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);

        mocks.ReplayAll();

        // Set controllerContext
        controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
}

5

Est AjaxRequest est une méthode d'extension. Vous pouvez donc le faire de la manière suivante en utilisant Rhino:

    protected HttpContextBase BuildHttpContextStub(bool isAjaxRequest)
    {
        var httpRequestBase = MockRepository.GenerateStub<HttpRequestBase>();   
        if (isAjaxRequest)
        {
            httpRequestBase.Stub(r => r["X-Requested-With"]).Return("XMLHttpRequest");
        }

        var httpContextBase = MockRepository.GenerateStub<HttpContextBase>();
        httpContextBase.Stub(c => c.Request).Return(httpRequestBase);

        return httpContextBase;
    }

    // Build controller
    ....
    controller.ControllerContext = new ControllerContext(BuildHttpContextStub(true), new RouteData(), controller);

4

On dirait que vous cherchez ceci,

 var requestMock = new Mock<HttpRequestBase>();
 requestMock.SetupGet(rq => rq["Age"]).Returns("2001");

Utilisation dans le contrôleur:

 public ActionResult Index()
 {
        var age = Request["Age"]; //This will return 2001
 }

3

Vous devez simuler HttpContextBase et le mettre dans votre propriété ControllerContext, comme ça:

controller.ControllerContext = 
new ControllerContext(mockedHttpContext, new RouteData(), controller);

et de quoi mockedHttpContext aurait-il besoin d'être moqué? L'objet RequestContext dont il a besoin a besoin d'un objet HttpContextBase () dans le constructeur, et HttpContextBase () n'a pas de constructeur qui n'accepte aucun paramètre.
Nissan

J'ai essayé: var mocks = new MockRepository (); var mockedhttpContext = mocks.DynamicMock <HttpContextBase> (); var mockedHttpRequest = mocks.DynamicMock <HttpRequestBase> (); SetupResult.For (mockedhttpContext.Request) .Return (mockedHttpRequest); var controller = new HomeController (Repository, LoginInfoProvider); controller.ControllerContext = new mockedhttpContext, new RouteData (), controller); var result = controller.Index () as ViewResult; Cependant, obtenez toujours la même exception levée.
Nissan

Votre lien ne fonctionne pas, mais ce qui suit semble fonctionner _request.Setup (o => o.Form) .Returns (new NameValueCollection ());
Vdex

2

Pour rendre IsAjaxRequest()faux pendant le test unitaire, vous devez configurer les en-têtes de demande ainsi que la valeur de collecte de la demande dans votre méthode de test, comme indiqué ci-dessous:

_request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "NotAjaxRequest" } });
_request.SetupGet(x=>x["X-Requested-With"]).Returns("NotAjaxRequest");

La raison de la configuration des deux est cachée dans l'implémentation de IsAjaxRequest () qui est donnée ci-dessous:

public static bool IsAjaxRequest(this HttpRequestBase request)<br/>
{ 
    if (request == null)
    {
        throw new ArgumentNullException("request");
    }
    return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest")));
}

Il utilise à la fois la collection de demandes et l'en-tête, c'est pourquoi nous devons créer une configuration pour l'en-tête et la collection de demandes.

cela rendra la demande de retour false quand ce n'est pas une demande ajax. pour le rendre vrai, vous pouvez faire ce qui suit:

_httpContext.SetupGet(x => x.Request["X-Requested-With"]).Returns("XMLHttpRequest");

0

J'ai trouvé un autre moyen d'ajouter un objet HttpRequestMessage dans votre demande pendant l'API Web comme suit

[Test]
public void TestMethod()
{
    var controllerContext = new HttpControllerContext();
    var request = new HttpRequestMessage();
    request.Headers.Add("TestHeader", "TestHeader");
    controllerContext.Request = request;
    _controller.ControllerContext = controllerContext;

    var result = _controller.YourAPIMethod();
    //Your assertion
}

0

(Un peu tard à la fête mais je suis allé pour un itinéraire différent alors j'ai pensé partager)

Pour opter pour une méthode pure code / moqueuse de tester cela sans créer de simulations pour les classes Http, j'ai implémenté un IControllerHelper qui a une méthode Initialise qui prend la Request comme paramètre, puis expose les propriétés que je veux, par exemple:

    public interface IControllerHelper
    {
        void Initialise(HttpRequest request);
        string HostAddress { get; }
    }

    public class ControllerHelper : IControllerHelper
    {
        private HttpRequest _request;
        
        public void Initialise(HttpRequest request)
        {
            _request = request;
        }

        public string HostAddress =>  _request.GetUri().GetLeftPart(UriPartial.Authority);
    }

Ensuite, dans mon contrôleur, j'appelle initialise au début de la méthode:

        _controllerHelper.Initialise(Request);

Et puis mon code ne dépend que de dépendances moquables.

        return Created(new Uri($"{_controllerHelper.HostName}/api/MyEndpoint/{result.id}"), result);

Pour les tests fonctionnels, je remplace simplement iControllerHelper dans la composition pour un substitut.

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.