Làm cách nào để giả lập Yêu cầu trên Trình điều khiển trong ASP.Net MVC?


171

Tôi có một bộ điều khiển trong C # bằng cách sử dụng khung công tác ASP.Net MVC

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

Tôi có một số mẹo về chế giễu và hy vọng sẽ kiểm tra mã với các điều sau đây và 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);

Tuy nhiên tôi vẫn nhận được lỗi này:

Hệ thống ngoại lệ.ArgumentNullException: System.ArgumentNullException: Giá trị không thể rỗng. Tên tham số: request tại System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest (yêu cầu httpRequestBase)

Requestđối tượng trên bộ điều khiển không có setter. Tôi đã cố gắng để thử nghiệm này hoạt động đúng bằng cách sử dụng mã được đề xuất từ ​​câu trả lời bên dưới.

Điều này đã sử dụng Moq thay vì RhinoMocks và khi sử dụng Moq tôi sử dụng cách sau cho cùng một bài kiểm tra:

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

nhưng nhận được lỗi sau:

Hệ thống ngoại lệ.ArgumentException: System.ArgumentException: Thiết lập không hợp lệ trên một thành viên không thể ghi đè: x => x.Headers ["X-Requested-With"] tại Moq.Mock.Throw IfCantOverride (Thiết lập biểu thức, phương thứcInInfo)

Một lần nữa, có vẻ như tôi không thể đặt tiêu đề yêu cầu. Làm cách nào để đặt giá trị này, trong RhinoMocks hoặc Moq?


Thay thế Request.IsAjaxRequest bằng Request.IsAjaxRequest ()
eu-ge-ne

Mock Request.Headers ["X-Requested-With"] hoặc Request ["X-Requested-With"] thay vì Request.IsAjaxRequest (). Tôi đã cập nhật câu hỏi của mình
eu-ge-ne

Câu trả lời:


211

Sử dụng 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);

CẬP NHẬT:

Mock Request.Headers["X-Requested-With"]hoặc Request["X-Requested-With"]thay vì Request.IsAjaxRequest().


1
Tôi nhận được thông báo "Đối số loại cho phương thức 'ISetupGetter <T, TProperty> Moq.Mock <T>. SetupGet <Tpropert> .... không thể được suy ra từ uage. Hãy thử xác định rõ loại đối số loại. 'var request =' mặc dù để làm cho điều này hoạt động?
Nissan

Chỉ cần cập nhật câu trả lời của tôi - không phải Request.IsAjaxRequest mà là Request.IsAjaxRequest (). Cập nhật câu hỏi của bạn quá
eu-ge-ne

Vẫn tạo: Ngoại lệ System.ArgumentException: System.ArgumentException: cài đặt không hợp lệ trên một thành viên phi overridable: x => x.IsAjaxRequest () tại Moq.Mock.ThrowIfCantOverride (cài đặt Expression, MethodInfo MethodInfo)
Nissan

Vấn đề là IsAjaxRequest () là phương thức mở rộng tĩnh và không thể bị chế giễu - Tôi đã cập nhật câu trả lời của mình.
eu-ge-ne

nên là bối cảnh.SetupGet (x => x.Request) .Returns (request.Object); mã của bạn ở trên bị thiếu 's' khi trả về Vẫn còn kết quả trong Hệ thống ngoại lệ.ArgumentException: System.ArgumentException: Thiết lập không hợp lệ trên một thành viên không thể ghi đè: x => x.Headers ["X-Requested-With"] tại Moq Thông báo lỗi .Mock.Throw IfCantOverride (Thiết lập biểu thức, phương thứcInInfoInInfo)
Nissan

17

Đối với bất kỳ ai sử dụng NSubstolarship tôi đã có thể sửa đổi các câu trả lời ở trên và làm một cái gì đó như thế này ... (trong đó Chi tiết là tên phương thức Hành động trên bộ điều khiển)

 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

Đây là một giải pháp làm việc bằng cách sử dụng RhinoMocks. Tôi đã dựa trên giải pháp Moq mà tôi tìm thấy tại 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

Có phải AjaxRequest là một phương thức mở rộng. Vì vậy, bạn có thể làm theo cách sau bằng 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

Có vẻ như bạn đang tìm kiếm điều này,

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

Sử dụng trong Bộ điều khiển:

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

3

Bạn cần phải giả lập HTTPContextBase và đặt nó vào thuộc tính ControllerContext của bạn, như thế:

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

và những gì sẽ bị chế giễuHttpContext cần phải được chế giễu? Đối tượng RequestContext mà nó yêu cầu cần một đối tượng HttpContextBase () trong hàm tạo và HTTPContextBase () không có hàm tạo chấp nhận tham số zero.
Nissan

Tôi đã thử: var mocks = new MockRep repository (); var mockedhttpContext = mocks.DocateMock <HttpContextBase> (); var mockedHttpRequest = mocks.DocateMock <HttpRequestBase> (); SetupResult.For (mockedhttpContext.Request) .Return (mockedHttpRequest); var điều khiển = HomeContoder mới (Kho lưu trữ, LoginInfoProvider); control.ControllContext = new mockedhttpContext, new RouteData (), bộ điều khiển); var result = control.Index () là ViewResult; Tuy nhiên vẫn nhận được ngoại lệ tương tự ném.
Nissan

Liên kết của bạn không hoạt động, nhưng những điều sau đây dường như hoạt động _request.Setup (o => o.Form) .Returns (new NameValueCollection ());
Vdex

2

Để IsAjaxRequest()trả về sai trong quá trình kiểm tra Đơn vị, bạn cần thiết lập Tiêu đề yêu cầu cũng như giá trị thu thập yêu cầu cả trong phương thức kiểm tra của bạn như được đưa ra dưới đây:

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

Lý do thiết lập cả hai được ẩn trong việc triển khai IsAjaxRequest () được đưa ra dưới đây:

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

Nó sử dụng cả Bộ sưu tập yêu cầu và tiêu đề, đây là lý do tại sao chúng ta cần tạo thiết lập cho cả Tiêu đề và Bộ sưu tập Yêu cầu.

điều này sẽ làm cho yêu cầu trả về false khi nó không phải là yêu cầu ajax. để làm cho nó trở lại đúng, bạn có thể làm như sau:

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

0

Tôi đã tìm thấy một cách khác để thêm một đối tượng HttpRequestMessage vào yêu cầu của bạn trong API Web như sau

[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

(Một chút đến bữa tiệc nhưng tôi đã đi một con đường khác nên tôi nghĩ tôi sẽ chia sẻ)

Để thực hiện một cách thử nghiệm mã / mô phỏng thuần túy mà không tạo ra các giả định cho các lớp http, tôi đã triển khai một IControllHelper có phương thức Khởi tạo lấy Yêu cầu làm tham số và sau đó hiển thị các thuộc tính tôi muốn, ví dụ:

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

Sau đó, trong bộ điều khiển của tôi, tôi gọi khởi tạo khi bắt đầu phương thức:

        _controllerHelper.Initialise(Request);

Và sau đó mã của tôi chỉ phụ thuộc vào các phụ thuộc có thể nhạo báng.

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

Đối với các bài kiểm tra chức năng, tôi chỉ ghi đè lên iControllHelper trong chế phẩm để thay thế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.