سؤال

لذلك يعتمد سياق وحدة التحكم على بعض الأجزاء الداخلية لـ asp.net.ما هي بعض الطرق للسخرية من هذه الاختبارات بشكل نظيف؟يبدو أنه من السهل جدًا إعاقة الاختبارات بالكثير من الإعدادات عندما أحتاج فقط، على سبيل المثال، إلى Request.HttpMethod لإرجاع "GET".

لقد رأيت بعض الأمثلة/المساعدين على الشبكات، ولكن بعضها قديم.اعتقدت أن هذا سيكون مكانًا جيدًا للاحتفاظ بالأحدث والأفضل.

أنا أستخدم أحدث إصدار من نماذج وحيد القرن

هل كانت مفيدة؟

المحلول

باستخدام MoQ يبدو الأمر كما يلي:

var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object
, new RouteData(), new Mock<ControllerBase>().Object);

أعتقد أن بناء جملة Rhino Mocks مشابه.

نصائح أخرى

إليك نموذجًا لفئة اختبار الوحدة باستخدام MsTest وMoq الذي يسخر من كائنات HttpRequest وHttpResponse.(.NET 4.0، ASP.NET MVC 3.0)

يحصل إجراء وحدة التحكم على قيمة من الطلب ويقوم بتعيين رأس http في كائنات الاستجابة.يمكن الاستهزاء بكائنات سياق http الأخرى بطريقة مماثلة

[TestClass]
public class MyControllerTest
{
    protected Mock<HttpContextBase> HttpContextBaseMock;
    protected Mock<HttpRequestBase> HttpRequestMock;
    protected Mock<HttpResponseBase> HttpResponseMock;

    [TestInitialize]
    public void TestInitialize()
    {
        HttpContextBaseMock = new Mock<HttpContextBase>();
        HttpRequestMock = new Mock<HttpRequestBase>();
        HttpResponseMock = new Mock<HttpResponseBase>();
        HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object);
        HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object);
    }

    protected MyController SetupController()
    {
        var routes = new RouteCollection();
        var controller = new MyController();
        controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller);
        controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes);
        return controller;
    }

    [TestMethod]
    public void IndexTest()
    {
        HttpRequestMock.Setup(x => x["x"]).Returns("1");
        HttpResponseMock.Setup(x => x.AddHeader("name", "value"));

        var controller = SetupController();
        var result = controller.Index();
        Assert.AreEqual("1", result.Content);

        HttpRequestMock.VerifyAll();
        HttpResponseMock.VerifyAll();
    }
}

public class MyController : Controller
{
    public ContentResult Index()
    {
        var x = Request["x"];
        Response.AddHeader("name", "value");
        return Content(x);
    }
}

إليك مقتطف من رابط جيسون.إنها نفس طريقة فيل ولكنها تستخدم وحيد القرن.

ملحوظة:تم إيقاف mockHttpContext.Request لإرجاع mockRequest قبل تم إيقاف العناصر الداخلية لـ mockRequest.أعتقد أن هذا الأمر مطلوب.

// create a fake web context
var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
var mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
mockHttpContext.Stub(x => x.Request).Return(mockRequest);

// tell the mock to return "GET" when HttpMethod is called
mockRequest.Stub(x => x.HttpMethod).Return("GET");            

var controller = new AccountController();

// assign the fake context
var context = new ControllerContext(mockHttpContext, 
                  new RouteData(), 
                  controller);
controller.ControllerContext = context;

// act
...

يبدو أن الإجراء الخاص بذلك قد تغير قليلاً في MVC2 (أنا أستخدم RC1).لا يعمل حل Phil Haack بالنسبة لي إذا كان الإجراء يتطلب طريقة محددة ([HttpPost], [HttpGet]).أثناء التجول في الكهوف في Reflector، يبدو أن طريقة التحقق من هذه السمات قد تغيرت.يتحقق MVC الآن request.Headers, request.Form, ، و request.QueryString ل X-HTTP-Method-Override قيمة.

إذا قمت بإضافة نماذج وهمية لهذه الخصائص، فإنها تعمل:

var request = new Mock<HttpRequestBase>();
request.Setup(r => r.HttpMethod).Returns("POST");
request.Setup(r => r.Headers).Returns(new NameValueCollection());
request.Setup(r => r.Form).Returns(new NameValueCollection());
request.Setup(r => r.QueryString).Returns(new NameValueCollection());

var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);

أو يمكنك القيام بذلك باستخدام Typemock Isolator دون الحاجة إلى إرسال وحدة تحكم زائفة على الإطلاق:

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");

لقد انتهيت من هذه المواصفات

public abstract class Specification <C> where C: Controller
{
    protected C controller;

    HttpContextBase mockHttpContext;
    HttpRequestBase mockRequest;

    protected Exception ExceptionThrown { get; private set; }

    [SetUp]
    public void Setup()
    {
        mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
        mockRequest = MockRepository.GenerateMock<HttpRequestBase>();

        mockHttpContext.Stub(x => x.Request).Return(mockRequest);
        mockRequest.Stub(x => x.HttpMethod).Return("GET");


        EstablishContext();
        SetHttpContext();

        try
        {
            When();
        }
        catch (Exception exc)
        {
            ExceptionThrown = exc;
        }
    }

    protected void SetHttpContext()
    {
        var context = new ControllerContext(mockHttpContext, new RouteData(), controller);
        controller.ControllerContext = context;
    }

    protected T Mock<T>() where T: class
    {
        return MockRepository.GenerateMock<T>();
    }

    protected abstract void EstablishContext();
    protected abstract void When();

    [TearDown]
    public virtual void TearDown()
    {
    }
} 

والعصير هنا

[TestFixture]
public class When_invoking_ManageUsersControllers_Update :Specification   <ManageUsersController>
{
    private IUserRepository userRepository;
    FormCollection form;

    ActionResult result;
    User retUser;

    protected override void EstablishContext()
    {
        userRepository = Mock<IUserRepository>();
        controller = new ManageUsersController(userRepository);

        retUser = new User();
        userRepository.Expect(x => x.GetById(5)).Return(retUser);
        userRepository.Expect(x => x.Update(retUser));

        form = new FormCollection();
        form["IdUser"] = 5.ToString();
        form["Name"] = 5.ToString();
        form["Surename"] = 5.ToString();
        form["Login"] = 5.ToString();
        form["Password"] = 5.ToString();
    }

    protected override void When()
    {
        result = controller.Edit(5, form);
    }

    [Test]
    public void is_retrieved_before_update_original_user()
    {
        userRepository.AssertWasCalled(x => x.GetById(5));
        userRepository.AssertWasCalled(x => x.Update(retUser));
    }
}

يتمتع

أجد أن هذا الإجراء الاستهزائي الطويل يمثل الكثير من الاحتكاك.

أفضل طريقة وجدناها - باستخدام ASP.NET MVC في مشروع حقيقي - هي تجريد HttpContext إلى واجهة IWebContext التي تمر عبرها ببساطة.ثم يمكنك الاستهزاء بـ IWebContext دون أي ألم.

هنا مثال

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top