Wie verspotte ich die Request on Controller in ASP.Net MVC?

171

Ich habe einen Controller in C #, der das ASP.Net MVC-Framework verwendet

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

Ich bekam einige Tipps zum Verspotten und hoffte, den Code mit den folgenden und RhinoMocks testen zu können

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);

Ich erhalte jedoch immer wieder diesen Fehler:

Ausnahme System.ArgumentNullException: System.ArgumentNullException: Wert darf nicht null sein. Parametername: Anforderung bei System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest (HttpRequestBase-Anforderung)

Seit der Request Objekt auf der Steuerung keinen Setter hat. Ich habe versucht, diesen Test ordnungsgemäß zu verwenden, indem ich den empfohlenen Code aus einer Antwort unten verwendet habe.

Dies verwendete Moq anstelle von RhinoMocks, und bei der Verwendung von Moq verwende ich Folgendes für denselben 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);

aber erhalte den folgenden Fehler:

Ausnahme System.ArgumentException: System.ArgumentException: Ungültiges Setup für ein nicht überschreibbares Mitglied: x => x.Headers ["X-Requested-With"] bei Moq.Mock.ThrowIfCantOverride (Ausdrucksetup, MethodInfo methodInfo)

Wieder scheint es, als könnte ich den Anforderungsheader nicht setzen. Wie setze ich diesen Wert in RhinoMocks oder Moq?

Nissan
quelle
Ersetzen Sie Request.IsAjaxRequest durch Request.IsAjaxRequest ()
eu-ge-ne
Mock Request.Headers ["X-Requested-With"] oder Request ["X-Requested-With"] anstelle von Request.IsAjaxRequest (). Ich habe meine Frage aktualisiert
eu-ge-ne
versuchen Sie dies
danfromisrael

Antworten:

211

Verwenden von 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);

AKTUALISIERT:

Mock Request.Headers["X-Requested-With"]oder Request["X-Requested-With"]statt Request.IsAjaxRequest().

eu-ge-ne
quelle
1
Ich erhalte die Meldung "Das Type-Argument für die Methode 'ISetupGetter <T, TProperty> Moq.Mock <T> .SetupGet <Tpropert> .... kann nicht aus uage abgeleitet werden. Versuchen Sie, die Typargumente explizit anzugeben. Welchen Typ setze ich 'var request =' um dies zum Laufen zu bringen?
Nissan
Ich habe gerade meine Antwort aktualisiert - nicht Request.IsAjaxRequest, sondern Request.IsAjaxRequest (). Aktualisieren Sie auch Ihre Frage
eu-ge-ne
Generiert weiterhin: Ausnahme System.ArgumentException: System.ArgumentException: Ungültiges Setup für ein nicht überschreibbares Element: x => x.IsAjaxRequest () bei Moq.Mock.ThrowIfCantOverride (Ausdrucks-Setup, MethodInfo methodInfo)
Nissan
Das Problem ist, dass IsAjaxRequest () eine statische Erweiterungsmethode ist und nicht verspottet werden kann - ich habe meine Antwort aktualisiert.
eu-ge-ne
sollte context.SetupGet (x => x.Request) sein .Returns (request.Object); In Ihrem obigen Code fehlt das 's' bei der Rückgabe. Dies führt auch zu einer Ausnahme. System.ArgumentException: System.ArgumentException: Ungültiges Setup für ein nicht überschreibbares Mitglied: x => x.Headers ["X-Requested-With"] bei Moq .Mock.ThrowIfCantOverride (Ausdruck einrichten, MethodInfo methodInfo) Fehlermeldung
Nissan
17

Für jeden, der NSubstitute verwendet, konnte ich die obigen Antworten ändern und so etwas tun ... (wobei Details der Name der Aktionsmethode auf dem Controller ist)

 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);
sjmarsh
quelle
13

Hier ist eine funktionierende Lösung mit RhinoMocks. Ich habe es auf einer Moq-Lösung basiert, die ich unter http://thegrayzone.co.uk/blog/2010/03/mocking-request-isajaxrequest/ gefunden habe.

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);
}
Phil Hale
quelle
5

Ist AjaxRequest ist eine Erweiterungsmethode. Mit Rhino können Sie dies folgendermaßen tun:

    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);
Jeroen Bernsen
quelle
4

Sieht so aus, als ob Sie danach suchen,

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

Verwendung in Controller:

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

Sie müssen HttpContextBase verspotten und wie folgt in Ihre ControllerContext-Eigenschaft einfügen:

controller.ControllerContext = 
new ControllerContext(mockedHttpContext, new RouteData(), controller);
Michał Chaniewski
quelle
und was müsste mockedHttpContext verspottet werden? Das erforderliche RequestContext-Objekt benötigt ein HttpContextBase () -Objekt im Konstruktor, und HttpContextBase () verfügt über keinen Konstruktor, der Nullparameter akzeptiert.
Nissan
Ich habe versucht: var mocks = new MockRepository (); var mockedhttpContext = mocks.DynamicMock <HttpContextBase> (); var mockedHttpRequest = mocks.DynamicMock <HttpRequestBase> (); SetupResult.For (mockedhttpContext.Request) .Return (mockedHttpRequest); var controller = neuer HomeController (Repository, LoginInfoProvider); controller.ControllerContext = neuer mockedhttpContext, neuer RouteData (), Controller); var result = controller.Index () als ViewResult; Es wird jedoch immer noch die gleiche Ausnahme ausgelöst.
Nissan
Ihr Link funktioniert nicht, aber das Folgende scheint zu funktionieren: _request.Setup (o => o.Form) .Returns (new NameValueCollection ());
Vdex
2

Um IsAjaxRequest()während des Komponententests false zurückzugeben, müssen Sie die Anforderungsheader sowie den Anforderungserfassungswert in Ihrer Testmethode wie folgt einrichten:

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

Der Grund für das Einrichten von beiden ist in der Implementierung von IsAjaxRequest () verborgen, die unten angegeben ist:

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")));
}

Es werden sowohl Anforderungssammlung als auch Header verwendet. Aus diesem Grund müssen wir ein Setup für Header und Anforderungssammlung erstellen.

Dadurch wird die Anforderung, false zurückzugeben, wenn es sich nicht um eine Ajax-Anforderung handelt. Damit es wahr wird, können Sie Folgendes tun:

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

Ich habe eine andere Möglichkeit gefunden, ein HttpRequestMessage-Objekt während der Web-API wie folgt zu Ihrer Anfrage hinzuzufügen

[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
}
Niraj Trivedi
quelle
0

(Ein bisschen spät zur Party, aber ich bin einen anderen Weg gegangen, also dachte ich, ich würde teilen)

Um dies zu testen, ohne Mocks für HTTP-Klassen zu erstellen, habe ich einen IControllerHelper implementiert, der über eine Initialisierungsmethode verfügt, die die Anforderung als Parameter verwendet und dann die gewünschten Eigenschaften verfügbar macht, z.

    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);
    }

Dann rufe ich in meinem Controller zu Beginn der Methode initialise auf:

        _controllerHelper.Initialise(Request);

Und dann ist mein Code nur von spöttischen Abhängigkeiten abhängig.

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

Für Funktionstests überschreibe ich einfach den iControllerHelper in der Komposition als Ersatz.

Stu
quelle