Кажется, не может установить объект при насмешливом HttpApplicationState с Moq - PullRequest
2 голосов
/ 29 августа 2011

У меня есть фильтр действий, который устанавливает объект в HttpApplicationState HttpContext контекста фильтра. Я хотел бы использовать эту функцию в модульном тесте, но по какой-то причине объект не устанавливается в базовом NameObjectCollectionBase, из которого происходит HttpApplicationState.

Я знаю, что функциональность работает, потому что когда я запускаю приложение MVC, оно работает как положено.

Как я могу настроить свой тест, чтобы заставить его устанавливать объекты в состоянии приложения? Я использую Moq и вот часть кода до сих пор. Не удается на

Asset.IsNotNull(context.HttpContext.Application["config"]);

Вот код.

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    ControllerBase controller = filterContext.Controller;
    if (!(controller is ApplicationController))
        return;

    ApplicationController applicationController = (ApplicationController) controller;

    IDictionary<string, string> config;

    // Loads the view configuration values.
    if (filterContext.HttpContext.Application["config"] == null)
    {
        config = applicationController.ApplicationService.GetConfiguration();
        filterContext.HttpContext.Application["config"] = config;
    }
    else
    {
        config = (IDictionary<string, string>) filterContext.HttpContext.Application["config"];
    }

    applicationController.ViewBag.BlogTitle = AddConfigurationValueToViewBag("BlogTitle", config);

}

Вот тест до сих пор.

[TestMethod]
public void ApplicationAttribute_OnActionExecuted_SetsConfigurationDctionaryInAppicationCache()
{
    // Arrange
    Mock<HttpContextBase> httpContext = new Mock<HttpContextBase>();

    var mockApplicationState = new Mock<HttpApplicationStateBase>();
    httpContext.Setup(h => h.Application).Returns(mockApplicationState.Object);

    ApplicationController applicationController = new BlogController(null, null, MocksAndStubs.CreateMockApplicationService());

    Mock<ActionExecutedContext> actionExecutedContext = new Mock<ActionExecutedContext>();
    actionExecutedContext.SetupGet(c => c.HttpContext).Returns(httpContext.Object);
    actionExecutedContext.SetupGet(c => c.Controller).Returns(applicationController);

    // Act
    ApplicationAttribute applicationAttribute = new ApplicationAttribute();
    ActionExecutedContext context = actionExecutedContext.Object;
    applicationAttribute.OnActionExecuted(context);

    // Assert
    Assert.IsNotNull(context.HttpContext.Application["config"]);
}

Ответы [ 2 ]

2 голосов
/ 29 августа 2011

Похоже, вы ожидаете, что ваш фиктивный объект будет более или менее действовать как реальный объект.Это не работает таким образом;макет будет делать только то, что вы говорите, не больше, не меньше.Если вы не говорите макету возвращать что-то конкретное при звонке.,.

context.HttpContext.Application["config"]

.,,тогда это просто не будет.Если вы настроили макет так, чтобы он возвращал что-то конкретное, это отрицательно сказалось бы на цели вашего теста.

Без какого-либо дополнительного понимания или вашей ситуации («что» и «почему» вашей тестовой стратегии), этоПохоже, вы пытаетесь убедиться, что набор состояния приложения вызывается.Я бы рекомендовал сделать mockApplicationState.Verify() в качестве вашего утверждения, чтобы проверить, что набор произошел , вместо того, чтобы проверять результирующее состояние самого объекта.

Редактировать: Проверить() позволяет утверждать / гарантировать, что метод (или метод свойства) был вызван с условиями или без них.Это должно помочь вам начать:

http://code.google.com/p/moq/wiki/QuickStart#Verification

Таким образом, ваша проверка будет выглядеть примерно так (полностью непроверено!):

mockApplicationState.Verify(x => x["config"] == [expected value], Times.Once());

Это в основном говорит о неудачной проверке, еслидля mockApplicationState ["config"] установлено ожидаемое значение менее одного раза или более одного раза.

Я предполагаю, что HttpApplicationStateBase не запечатан.Если это так, то приведенное выше может вызвать исключение.

0 голосов
/ 06 сентября 2016

В качестве альтернативы MOQ я часто в этом сценарии генерирую некоторые заглушки, полученные из базовых классов в System.Web.Abstractions.Я часто использую эту технику для приложений MVC, поскольку контроллеры MVC / WebApi содержат абстракцию к HttpContext (HttpContextBase)

Таким образом, я могу заглушить требования HttpContext в моих тестах модулей / интеграции, вот пример ...

public class MockHttpApplicationState : HttpApplicationStateBase
{
    private IDictionary<string, object> _appState = new Dictionary<string, object>();

    public override void Add(string name, object value)
    {
        _appState.Add(name, value);
    }

    public override object Get(string name)
    {
        return _appState[name];
    }

    public override object this[string name]
    {
        get
        {
            return _appState[name];
        }

        set
        {
            _appState[name] = value;
        }
    }
}

public class MockHttpContext : HttpContextBase
{
    private IDictionary<string, object> _appKeys;

    public MockHttpContext()
    {

    }

    /// <summary>
    /// Accepts a dictionary of app keys to supply to the HttpApplicationState instance
    /// </summary>
    /// <param name="applicationState"></param>
    public MockHttpContext(IDictionary<string,object> applicationState)
    {
        _appKeys = applicationState;
    }

    public override Cache Cache
    {
        get
        {                
            return HttpRuntime.Cache;
        }
    }

    public override HttpApplicationStateBase Application
    {
        get
        {
            var mockAppState = new MockHttpApplicationState();

            foreach (string key in _appKeys.Keys)
            {
                mockAppState.Add(key, _appKeys[key]);
            }

            return mockAppState;
        }
    }

    public override HttpRequestBase Request
    {
        get
        {
            return new HttpRequestWrapper(new HttpRequest(null,"http://localhost",null));
        }
    }
}

Тогда мой тест может установить Контроллер и Контекст Http:

private readonly OnlineShop.MVC.Controllers.HomeController _controller = 
        new MVC.Controllers.HomeController(null,new UnitOfWork());

    [OneTimeSetUp]
    public void Init()
    {
        var appKeys = new Dictionary<string, object>();

        appKeys.Add("localhost", 1);

        var httpContext = new MockHttpContext(appKeys);

        _controller.ControllerContext = new ControllerContext()
        {
            Controller = _controller,
            RequestContext = new RequestContext(httpContext, new RouteData())    
        };                        
    }

    [Test]
    public void Index_Returns_HomeView()
    {            
        var view = _controller.Index() as ViewResult;
        var viewModel = view.Model as MVC.ViewModels.Home;

        Assert.IsInstanceOf<OnlineShop.MVC.ViewModels.Home>(viewModel);
        Assert.IsTrue(viewModel.FeaturedProducts.Count > 0);
    }

И мой контроллер знает, что его окружающий экземпляр HttpContextBase предоставляет состояние Cache и Application:

  public ActionResult Index()
    {                        
        string cacheKey = string.Format("FeaturedProducts-{0}",WebsiteId);
        IList<Product> productList = this.HttpContext.Cache[cacheKey] as IList<Product>;


        //My app keeps a list of website contexts in the Application. This test returns 1 based on the unit / int tests or a real world db value when hosted on IIS etc..
        int websiteId = (int)HttpContext.Application[this.Request.Url.Host];
...