1

我正在构建一个 ASP.NET MVC4 应用程序。我没有使用任何模拟框架,如果可能的话,我现在不希望这样做。我的问题是两部分。

我有一个控制器,它使用在 Global.asax 中创建的变量。在控制器中,我像这样访问变量。

HttpContext.Application["MyVar"]

1)这是应用程序范围内变量使用的最佳实践吗?如果没有,最好的方法是什么?

为了对该控制器进行单元测试,我将以下代码(从此处)添加到我的测试方法中。

MyController target = new MyController();
var request = new HttpRequest("", "http://example.com/", "");
var response = new HttpResponse(System.IO.TextWriter.Null);
var httpContext = new HttpContextWrapper(new HttpContext(request, response));
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
target.ControllerContext.HttpContext.Application["MyVar"] = new MyVar();

问题是我无法向应用程序添加任何内容。最后一行代码似乎没有做任何事情,集合仍然是空的。我也在 VS 的即时窗口中尝试过,但没有成功。

2)在单元测试中,如何添加控制器需要的应用级变量?

4

2 回答 2

1

一般来说,全局变量不适合测试。您至少可以采取两种方法。

  1. 使用Pex/Moles、NMock 等模拟框架。

  2. 使用控制反转的方法(我最喜欢NInject)。如果像控制器这样的类具有外部依赖项,它会请求接口,通常在其构造函数中。

    私有只读 IApplicationSettings _settings;

    公共 MyController(IApplicationSettings 设置){ _settings = 设置;}

    无效 someMethod() { _settings.Get("MyVar"); }

通过这种方式,您可以编写真实的和测试的实现。

public LiveAppSettings : IApplicationSettings
{
    public string Get(string key)
    { 
        return HttpContext.Current.Application[key];
    }
}

使用 Ninject,您可以在应用程序启动时绑定任一实现:

var kernel = new StandardKernel();
kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
于 2012-08-19T01:38:29.387 回答
0

这是应用程序范围内变量使用的最佳实践吗?

最佳实践有点主观的概念,在没有完全解释你的场景以及你想要实现的目标的情况下,我不想讨论它。

我们无法讨论这是否是最佳实践,但据我所知,这也没有错。这没有错,因为您使用的是允许对代码进行单元测试的抽象。

在单元测试中,如何添加控制器需要的应用程序级变量?

您可以使用诸如 Rhino Mocks 之类的模拟框架来模拟控制器所需的抽象。我们以下面的控制器为例:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var myVar = (MyVar)HttpContext.Application["MyVar"];
        return Content(myVar.Foo);
    }
}

我们想对 Index 操作进行单元测试。这是一个示例单元测试:

[TestMethod]
public void Index_Action_Should_Retrieve_MyVal_From_AppState()
{
    // arrange
    var target = new HomeController();
    var httpContext = MockRepository.GeneratePartialMock<HttpContextBase>();
    var application = MockRepository.GeneratePartialMock<HttpApplicationStateBase>();
    application.Expect(x => x["MyVar"]).Return(new MyVar { Foo = "bar" });
    httpContext.Expect(x => x.Application).Return(application);
    target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);

    // act
    var actual = target.Index() as ContentResult;

    // assert
    Assert.AreEqual("bar", actual.Content);
}
于 2012-08-19T06:13:33.680 回答