Вопрос

Поэтому контекст контроллера зависит от ряда внутренних органов asp.net .Каковы некоторые способы чисто смоделировать их для модульных тестов?Похоже, что очень легко засорить тесты тоннами настроек, когда мне нужно только, например, запросить.HttpMethod возвращает "GET".

Я видел несколько примеров / помощников в сети, но некоторые из них устарели.Подумал, что это было бы хорошим местом для хранения самых последних и замечательных вещей.

Я использую последнюю версию rhino mocks

Это было полезно?

Решение

Используя 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);
    }
}

Вот фрагмент из ссылки Джейсона.Это тот же метод, что и у Фила, но используется rhino.

Примечание: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).Решение Фила Хаака для меня не работает, если действие требует определенного метода ([HttpPost], [HttpGet]).Покопавшись в Reflector, похоже, что метод проверки этих атрибутов изменился.Теперь MVC проверяет request.Headers, request.Form, и request.QueryString для X-HTTP-Method-Override ценность.

Если вы добавите mocks для этих свойств, это сработает:

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