Bagaimana cara mengejek Permintaan Pengontrol di ASP.Net MVC?

171

Saya memiliki pengontrol di C # menggunakan kerangka ASP.Net MVC

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

Saya mendapat beberapa tip tentang mengejek dan berharap untuk menguji kode dengan yang berikut dan 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);

Namun saya terus mendapatkan kesalahan ini:

Exception System.ArgumentNullException: System.ArgumentNullException: Nilai tidak boleh nol. Nama parameter: permintaan di System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest (permintaan HttpRequestBase)

Karena Requestobjek pada pengontrol tidak memiliki setter. Saya mencoba agar tes ini berfungsi dengan baik dengan menggunakan kode yang disarankan dari jawaban di bawah ini.

Ini menggunakan Moq alih-alih RhinoMocks, dan dalam menggunakan Moq saya menggunakan yang berikut untuk tes yang sama:

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

tetapi dapatkan kesalahan berikut:

Exception System.ArgumentException: System.ArgumentException: Penyiapan yang tidak valid pada anggota yang tidak dapat ditimpa: x => x.Headers ["X-Diminta-Dengan"] di Moq.Mock.ThrowIfCantOverride (Penyiapan Ekspresi, penyiapan Metode, MetodeInfo metodeInfo)

Sekali lagi, sepertinya saya tidak bisa mengatur header permintaan. Bagaimana cara menetapkan nilai ini, dalam RhinoMocks atau Moq?

Nissan
sumber
Ganti Request.IsAjaxRequest dengan Request.IsAjaxRequest ()
eu-ge-ne
Mock Request.Headers ["X-Requested-With"] atau Request ["X-Requested-With"] bukannya Request.IsAjaxRequest (). Saya telah memperbarui pertanyaan saya
eu-ge-ne
coba ini
danfromisrael

Jawaban:

212

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

DIPERBARUI:

Mengejek Request.Headers["X-Requested-With"]atau Request["X-Requested-With"]bukannya Request.IsAjaxRequest().

eu-ge-ne
sumber
1
Saya mendapatkan pesan "Argumen Jenis untuk metode 'ISetupGetter <T, TProperty> Moq.Mock <T> .SetupGet <Tpropert> .... tidak dapat disimpulkan dari uage. Coba tentukan jenis argumen secara eksplisit. Jenis apa yang saya setel 'var request =' meskipun untuk mendapatkan ini berfungsi?
Nissan
Baru saja memperbarui jawaban saya - bukan Request.IsAjaxRequest tetapi Request.IsAjaxRequest (). Perbarui pertanyaan Anda juga
eu-ge-ne
Masih menghasilkan: Exception System.ArgumentException: System.ArgumentException: Penyiapan yang tidak valid pada anggota yang tidak dapat ditimpa: x => x.IsAjaxRequest () di Moq.Mock.ThrowIfCantOverride (Penyiapan Ekspresi, MetodeInfo metodeInfo)
Nissan
Masalahnya adalah IsAjaxRequest () adalah metode ekstensi statis dan tidak dapat diejek - Saya telah memperbarui jawaban saya.
eu-ge-ne
harus berupa context.SetupGet (x => x.Request) .Returns (request.Object); kode Anda di atas tidak ada 's' saat Pengembalian masih juga menghasilkan Exception System.ArgumentException: System.ArgumentException: Pengaturan tidak valid pada anggota yang tidak dapat ditimpa: x => x.Headers ["X-Diminta-Dengan"] di Moq .Mock.ThrowIfCantOverride (penyiapan ekspresi, MethodInfo methodInfo) pesan galat
Nissan
17

Bagi siapa pun yang menggunakan NSubstitute, saya dapat mengubah jawaban di atas dan melakukan sesuatu seperti ini ... (di mana Detail adalah nama metode Action pada controller)

 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
sumber
13

Ini adalah solusi yang berfungsi menggunakan RhinoMocks. Saya telah mendasarkannya pada solusi Moq yang saya temukan di 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);
}
Phil Hale
sumber
5

Is AjaxRequest adalah metode ekstensi. Jadi Anda bisa melakukannya dengan cara berikut menggunakan 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);
Jeroen Bernsen
sumber
4

Sepertinya Anda mencari ini,

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

Penggunaan dalam Kontroler:

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

Anda perlu mengejek HttpContextBase dan memasukkannya ke properti ControllerContext Anda, seperti itu:

controller.ControllerContext = 
new ControllerContext(mockedHttpContext, new RouteData(), controller);
Michał Chaniewski
sumber
dan apa yang perlu diejekHttpContext perlu diejek? Untuk objek RequestContext yang diperlukan, objek HttpContextBase () di konstruktor, dan HttpContextBase () tidak memiliki konstruktor yang menerima parameter nol.
Nissan
Saya mencoba: var mocks = new MockRepository (); var mockedhttpContext = mocks.DynamicMock <HttpContextBase> (); var mockedHttpRequest = mocks.DynamicMock <HttpRequestBase> (); SetupResult.For (mockedhttpContext.Request) .Return (mockedHttpRequest); var controller = HomeController baru (Repositori, LoginInfoProvider); controller.ControllerContext = new mockedhttpContext, baru RouteData (), controller); var result = controller.Index () sebagai ViewResult; Namun masih mendapatkan pengecualian yang sama dilemparkan.
Nissan
Tautan Anda tidak berfungsi, tetapi yang berikut tampaknya berfungsi _request.Setup (o => o.Form) .Returns (NameValueCollection baru ());
Vdex
2

Untuk membuat IsAjaxRequest()kesalahan kembali selama pengujian Unit, Anda perlu mengatur Header Permintaan serta nilai pengumpulan permintaan baik dalam metode pengujian Anda seperti yang diberikan di bawah ini:

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

Alasan pengaturan keduanya tersembunyi dalam implementasi IsAjaxRequest () yang diberikan di bawah ini:

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

Ia menggunakan kedua Koleksi permintaan dan tajuk ini sebabnya kami perlu membuat pengaturan untuk Koleksi Header dan Permintaan.

ini akan membuat permintaan untuk mengembalikan false ketika itu bukan permintaan ajax. untuk mengembalikannya, Anda dapat melakukan hal berikut:

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

Saya menemukan cara lain untuk menambahkan objek HttpRequestMessage ke dalam permintaan Anda selama API Web sebagai berikut

[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
sumber
0

(Agak terlambat ke pesta tapi aku pergi untuk rute yang berbeda jadi kupikir aku akan berbagi)

Untuk menggunakan kode murni / cara mengejek pengujian ini tanpa membuat tiruan untuk kelas Http saya menerapkan IControllerHelper yang memiliki metode Inisialisasi yang mengambil Permintaan sebagai parameter dan kemudian membuka properti yang saya inginkan misalnya:

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

Kemudian di pengontrol saya, saya sebut inisialisasi pada awal metode:

        _controllerHelper.Initialise(Request);

Dan kemudian kode saya hanya bergantung pada dependensi yang dapat diejek.

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

Untuk tes fungsional, saya hanya mengganti iControllerHelper dalam komposisi sebagai pengganti.

Stu
sumber