Unit Testing Application_Start - c#

I am looking for any kind of information (prefer Moq) on how to unit test the Application_Start method in Global.asax. I am using ASP.NET MVC and trying to get to that elusive 100% code coverage!
The fact that I'm using MVC is not the point. And saying that not testing Start is not necessary isn't really the answer either. What if I had other code in there? I need to know how to test it.

Some organizations do require those meaningless numbers, and have issues beyond cost. For companies dealing with $ensitive information "Good enough" is not good enough. I had exactly the same issue and like Klas Mellbourn, need to get to 100% (if not higher!)
The following worked for me. Although, I'd have preferred to mark it "Exclude from code coverage"
public class Global : HttpApplication
{
public override void Init()
{
AreaRegistration.RegisterAllAreas(); //will error out on app_start
base.Init();
}
/// <summary>
/// Application_Start method.
/// </summary>
/// <param name="sender">The caller</param>
/// <param name="e">The event arguments</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "KMM: This method is called dynamically by the framework.")]
protected void Application_Start(object sender, EventArgs e)
{
var container = StructureMapRegistry.Initialize();
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapResolver(container);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
Then the unit test looked like this:
public class GlobalTest : Global
{
private HttpRequestMessage FakeRequest;
DateTime? effectiveDate = DateTime.Now.AddYears(-4);
private string policyNumber = "1234567890";
[TestMethod]
public void ApplicationStart()
{
var sender = new object();
var e = new EventArgs();
try
{
Application_Start(sender, e); // this will error b/c not fully loaded yet.
}
catch (InvalidOperationException)
{
Thread.Sleep(2000); // give the app time to launch
Application_Start(sender, e);
}
Assert.IsTrue(true);
}
}
and finally, I needed to set a flag in my WebApiConfig to prevent the routes from being registered twice.
public static class WebApiConfig
{
private static bool isRegistered;
/// <summary>
/// Registers the configuration.
/// </summary>
/// <param name="config">The Http Configuration.</param>
public static void Register(HttpConfiguration config)
{
if (isRegistered)
{
return;
}
config.MapHttpAttributeRoutes();
Now, before the haters and purists start marking this down, the assignment is to test all code. I personally detest modifying code to suit tests. That's not the same thing as making code testable. Adding the isRegistered flag is an example of the sort of artifact that is necessary to support the test needing to call the app_start 2x. It's a small thing and since that code only gets called on app_start, I'm not going to fuss over it too much.
I would certainly be interested in what others have done in this regard.

In a typical ASP.NET MVC application the Application_Start event is often used to register custom routes. Here's a nice post explaining how to unit test your custom routes.

this function is called the first time your site is visited.
recycling the app pool will cause it to be triggered again
In most situations, this event handler has no code, so don't waste time pursuing meaningless numbers!

If you want to test the actions of an event-based item like this, separate the actions into a separate, testable method and just call it from the handler. Or, as darin suggested, test the effects of the method - in this particular case, that your routing table got registered correctly.
BTW, I've never reached 100% coverage on a non-trivial app... We generally target 80% as "good enough". Some modules are 100% testable, but many aren't practical to do so.

I've found the best way to unit test stuff in Global.asax is to make sure the whole thing is in a testable static method.
Then pass in to that method everything it needs from Global.asax.
So for example, if you were doing a check of Session on Application Start, you could have a method like this:
public static void CheckSession(HttpSessionStateBase session)
{
...
}
Then, your Application Start would just be this:
protected void Application_Start(object sender, EventArgs e)
{
CheckSession(new HttpSessionStateWrapper(Session));
}
This example is obviously a little silly as you'd probably do something like this in Session Start :) You could pass into that method whatever it needs, Request, Response, Cache, etc.
However, it gets the point across. The only code that wouldn't be covered would be the actual single line call in Application_Start. Everything else could be covered in a test using Moq like so:
var session = new Moq<HttpSessionStateBase>();
...Set Expectations...
Global.CheckSession(session.Object);
...Do Asserts...
You wouldn't achieve the 100% code coverage you're looking for, but you'd be darned close, and you would be fulfilling the "spirit" of TDD law if not exactly the letter :)

Related

Web API global setup code, also for unit tests

Say I have some global application setup code, defined in my Global.asax, Application_Start. For example to disable certificate checking:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// (...)
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// (...)
}
}
Say I also have a unit test, which depends on the code above to be run. However in my unit test, Application_Start is not called as I'm instantiating the controller directly:
var controller = new TestSubjectController();
Is there some mechanism in ASP.NET or Web API that solves this problem? What would be the best way to define the setup code, preventing duplication in my code?
Research
I've went through multiple questions on SO already. Most of them focus on unit testing Application_Start itself, however that's not the goal here. Other questions tend to look at testing using the applications external (HTTP) interface, however I'd like being able to instantiate the controller directly in my unit tests.
In addition to Batavia's suggestion you could use a [TestInitialize] attributed method or your unit testing framework of choices's equivalent to call the common static method for all tests in a certain class which would reduce the duplication you're concerned about.

Why are my HttpApplication instance variables null?

I have a MVC3 application to which I've added a couple of simple cache variables as a property. I add my data in Application_Start and then later in a controller try to cast the HttpContext.ApplicationInstance back to my type to access it. But, the property is always null. Here's an example:
EDITED TO WORKING EXAMPLE
public interface IMyMvcApp
{
Hashtable Cache {get;set;}
}
public class MvcApplication: HttpApplication, IMyMvcApp
{
public Hashtable Cache
{
get { return Context.Cache["MyStuff"] as Hashtable; }
set { Context.Cache["MyStuff"] = value}
}
public void Application_Start()
{
Cache = new Hashtable();
Cache.Add("key", new object());
}
}
public class AController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext context)
{
var myApp = context.HttpContext.ApplicationInstance as IMyMvcApp;
Assert.IsNotNull(myApp.Cache);
}
}
There are multiple instances of the application created by the framework. To verify this add an empty constructor and put a breakpoint in it. You will see that this constructor will be hit multiple times whereas the Application_Start only once.
So instead of reinventing wheels you should use the Cache object that's already built into the framework:
protected void Application_Start()
{
...
Context.Cache["key"] = new object();
}
and then:
protected override void OnActionExecuting(ActionExecutingContext context)
{
var value = context.HttpContext.Cache["key"];
}
In addition to Darin's correct answer recommending the builtin cache, a note on Singletons in Asp.Net.
MvcApplication is NOT a singleton
Contrary to very widespread belief, MvcApplication is NOT a global singleton. The class is instantiated several times, one instance per "pipeline", so the performance counter "pipeline instance count" tells you how many instances of MvcApplication are currently consdidered alive. Add a default ctor and prove this yourself:
public MvcApplication()
{
Trace.WriteLine(this.GetHashCode());
}
Debug break the line or watch the various hash codes in DebugViewer. To force pipeline instance count going up create a method with Thread.Sleep(5000), Asp.Net will then fire up a new instance once you make another http request in parallel.
Solution - How to instantiate singletons in Asp.Net applications (MVC or WebForms)
If your MvcApplication class however has an Application_Start() method then this method is called in fact only once, process wide. This allows adding static fields to MvcApplication and access them.
These fields are then accessed by
MvcApplication.MySingleValue
obviously.
HttpApplication weirdness
The design of the HttpApplication class and its events is quite strange, which presumably has its reason in some loose sort of backwards design compatibility to very old COM based ASP pages. There the application object was in fact created only once, which is surely the origin of the wrong belief related to Asp.Net. An example of the HttpApplication strangeness:
protected void Application_Start()
{
}
Note that there is no override involved!
In summary, the application instances might be of minor interest most of the time, I can see no scenario were it could become relevant to hold state, as its state would be shared by an arbitrary subset of requests handled. So accessing it in the completely fine way as mentioned by Matt might not be required too often.

what is the replacement for Application_Start in MVCTurbine?

Apparently, this method no longer gets called... In there we have code for configuring AutoMapper, and for setting model binders.
I know there is a "new" way to do model binders, but... shouldn't I still be able to do it "the old way" until I get that implemented?
Specifically, I have two lines left from my old Application_Start() method that I have been unable to get working:
AutoMapperConfiguration.Configure();
ModelBinders.Binders[typeof (ModuleEditModel)] = new DerivedModelBinder();
I've tried simply popping those into the constructor, right after the call to: ServiceLocatorManager.SetLocatorProvider(() => new StructureMapServiceLocator());
And that runs, but.. it seems somehow not to take effect. In running the application it is clear that AutoMapper isn't happy, doesn't have the mappings it is supposed to have, etc.
I answered this question out on the Turbine Discussion board on CodePlex. Here's the source for making the changes you ask for:
public class MvcApplication : TurbineApplication {
static MvcApplication() {
// Register the IoC that you want Mvc Turbine to use!
// Everything else is wired automatically
// For now, let's use the Unity IoC
ServiceLocatorManager.SetLocatorProvider(() => new UnityServiceLocator());
}
public override void Startup(){
// Gets called when the application starts up
// and before all the stuff that Turbine wires up
}
public override void Shutdown() {
// Gets called when the application shuts down
// and before any cleanup is done by Turbine
}
}
Hope this helps!

Custom C# HttpModule Infinite Redirect Loop

I am writing a custom c# HttpModule that will handle requests from all file types. As a simple proof of concept I have setup the module by adding a reference to the httpModules section of the web config and added application extensions for the demo IIS website with a reference to the aspnet_isapi.dll so that it currently only intercepts request for ".htm" files
But even if there is no significant code in the "OnBeginRequest" event (code below) it causes an infinite redirect loop. I am using IIS 5 on XP Anyone got any ideas?
So far I have only seen HttpModule examples for use with ASPX files but surely you can configure the for any file type?
#region IHttpModule Members
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
///
///
///
///
public void OnBeginRequest(Object s, EventArgs e)
{
HttpApplication context = s as HttpApplication;
Uri currentURL = context.Request.Url;
string pageName = currentURL.Segments.Last().ToLower();
}
#endregion
OK. The problem was actually in the HttpModule itself.
It appears that you have to use the HttpApplication context in order for it to render on the client.
For Example after you have performed all your custom logic you need to write to the context:
context.Response.Write("/n/r");
//or
context.Response.Redirect("test.htm");
Everything then renders as you would expect

Earliest access to the .net lifecycle

After looking at the .net on IIS7 application lifecycle:
http://msdn.microsoft.com/en-us/library/ms178473.aspx
For maximum performance, I want to find a way to get my code started as soon as the HttpContext object is created but before HttpApplication is. (it's easy to run code after the HttpApplication class is loaded but before any of it's event are triggered by using the contructor of an HTTP Module like this:
public class AuthModule : IHttpModule
{
public AuthModule()
{
HttpContext.Current.Response.Write("hello world");
HttpContext.Current.Response.End();
}
#region IHttpModule Members
public void Dispose()
{ }
public void Init(HttpApplication context)
{ }
#endregion
}
I know that i won't get access to the User object, but i won't need it.
You cannot ever be sure your code starts before the HttpApplication instance is created, since these instances may be reused.
Also, running code at this stage is beyond the scope of the pipeline. It should make you ask yourself whether it's really a sensible thing to do.
And what's this about performance? You really think the time to create an instance of HttpApplication is going to register in your performance?
Take a step back and reconsider.
Look at the life-cycle events on MSDN. You can consider using one of those events if you want something earlier than the normal page events.

Categories

Resources