Unit test controller that uses application scoped variables

前端 未结 2 521
伪装坚强ぢ
伪装坚强ぢ 2021-01-25 17:14

I\'m building an ASP.NET MVC4 app. I\'m not using any mocking framework and, if possible, would prefer not to at this point. My question is 2 parts.

I have a controll

相关标签:
2条回答
  • 2021-01-25 17:51

    Is this a best-practice for application wide variable usage?

    Best practice is a bit of a subjective notion and without fully explaining your scenario and what precisely are you trying to achieve I prefer not to discuss it.

    We cannot discuss whether this is best practice but from what I can see it is not wrong either. It is not wrong because you are using the abstractions allowing the code to be unit tested.

    In the unit test, how can I add the application level variables the controller needs?

    You could use a mocking framework such as Rhino Mocks to mock the abstractions that the controller needs. Let's take as an example the following controller:

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

    and we would like to unit test the Index action. Here's a sample unit test:

    [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);
    }
    
    0 讨论(0)
  • 2021-01-25 17:56

    In general globals aren't good for testing. There are at least two approaches you could take.

    1. Use a mocking framework like Pex/Moles, NMock, etc.

    2. Use an inversion-of-control approach (NInject is my favorite). If class like a controller has an external dependency, it asks for the interface, typically in its constructor.

      private readonly IApplicationSettings _settings;

      public MyController(IApplicationSettings settings) { _settings = settings; }

      void someMethod() { _settings.Get("MyVar"); }

    This way you can write real and test implementations.

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

    With Ninject, you can bind either implementation at application startup:

    var kernel = new StandardKernel();
    kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
    
    0 讨论(0)
提交回复
热议问题