Unit Test Web Code Without A Web Server Using HttpSimulator

asp.net, tdd 0 comments suggest edit

Testing code written for the web is challenging. Especially code that makes use of the ASP.NET intrinsic objects such as the HttpRequest object. My goal is to make testing such code easier.

Spider Web (c) FreeFoto.com

A while ago, I wrote some code to simulate the HttpContext in order to make writing such unit tests easier. My goal wasn’t to replace web testing frameworks such as Selenium, Watin, or AspUnit. Instead, I’m a fan of the Pareto principle and I hoped to help people easily reach the 80 of the 80/20 rule before reaching out to one of these tools to cover the last mile.

I’ve spent some time since then refactoring the code and improving the API. I also implemented some features that were lacking such as being able to call MapPath and setting and getting Session and Application variables.

To that end, I introduce the HttpSimulator class. To best demonstrate how to use it, I will present some unit test code.

The following code simulates a simple GET request for the web root with the physical location c:\inetpub. The actual path passed into the simulator doesn’t matter. It’s all simulated. This tests that you can set a session variable and then retrieve it.

[Test]
public void CanGetSetSession()
{
  using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest())
  {
    HttpContext.Current.Session["Test"] = "Success";
    Assert.AreEqual("Success", HttpContext.Current.Session["Test"]);
  }
}

The following test method demonstrates two different methods for simulating a form post. The second using block shows off the fluent interface.

[Test]
public void CanSimulateFormPost()
{
  using (HttpSimulator simulator = new HttpSimulator())
  {
    NameValueCollection form = new NameValueCollection();
    form.Add("Test1", "Value1");
    form.Add("Test2", "Value2");
    simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), form);

    Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]);
    Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]);
  }

  using (HttpSimulator simulator = new HttpSimulator())
  {
    simulator.SetFormVariable("Test1", "Value1")
      .SetFormVariable("Test2", "Value2")
      .SimulateRequest(new Uri("http://localhost/Test.aspx"));

    Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]);
    Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]);
  }
}

The SimulateRequest method is always called last once you’ve set your form or query string variables and whatnot. For read and write values such as session, you can set them after the call. If you download the code, you can see other usage examples in the unit tests.

One area I’ve had a lot of success with this class is in unit testing custom HttpHandlers. I’ve also use it to test custom control rendering code and helper methods for ASP.NET.

This code can be found in the Subtext.TestLibrary project in our Subversion repository. This project contains code I’ve found useful within my unit tests such as a test SMTP server and a test Web Server using WebServer.WebDev.

To make it easy for you to start using the HttpSimulator, I’ve packaged the relevant files in a zip file including the unit tests.

I must make one confession. I originally tried to do all this by using the public APIs. Unfortunately, so many classes are internal or sealed that I had to get my hands dirty and resort to using reflection. Doing so freed me up to finally get certain features working that I could not before.

And now, for some preemptive answers to expected criticism.

​1. You shouldn’t access the HttpContext anyways. You should abstract away the HttpContext by creating your own IContext and using IoC and Dependency Injection.

You’re absolutely right. Next criticism.

​2. This isn’t “unit testing”, this is “integration testing”.

Very astute observation. Well said. Next?

​3. You’re not taking our criticisms seriously!

Au contraire! I take such criticisms very seriously. Even if you write a bunch of code to abstract away the web from your code throwing all sorts of injections and inversions at it, you still have to test your abstraction. HttpSimulator to the rescue!

Likewise, whether this is unit testing or integration testing is splitting semantic hairs. Before TDD came along, unit testing meant testing a unit of code. It usually meant walking through the code line by line and executing a single function. If you want to call these integration tests, fine. HttpSimulator to the rescue!

Not to mention that in the real world, you sometimes don’t get to write code from scratch using sound TDD principles. A lot of time you inherit legacy code and the best you can do is try to write tests after-the-fact as you go before you refactor the code. Again, HttpSimulator to the rescue!

Here is the link todownload the source files in case you missed it the first time.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

81 responses

  1. Avatar for Julian Birch
    Julian Birch June 19th, 2007

    Extremely nice. Wish I'd had this a year ago...

  2. Avatar for Haacked
    Haacked June 19th, 2007

    @Julian - well the original version was written a year ago. ;)

  3. Avatar for DotNetKicks.com
    DotNetKicks.com June 19th, 2007

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  4. Avatar for Kevin Dente
    Kevin Dente June 19th, 2007

    Maybe we need a new term - they're unigration tests! ;)
    Have you checked out Plasma?
    http://www.codeplex.com/plasma

  5. Avatar for Chris May
    Chris May June 19th, 2007

    I am trying to use MVP on some of my webforms for testing purposes.
    Do you know if there is in depth/complex examples out there of how to go about doing this?
    I know there is a simple form example of MVP on this site, but I am looking for something a little more complex. I basically have 2 questions in my mind:
    1) Should the view "pull" its info, or should it be "pushed" to the view. Say for example you have something where a user enteres something in a textbox, clicks a button, and a datagrid is populated. You could have the view do this:
    controller.NewSearchEntered(this.txtSearch.Text())
    and the controller would do:
    void NewSearchEntered(string text){
    // get data from DB
    view.PopulateResults(someDataset);
    }
    but I have seen other people doing it where the view asks for it's information from the controller like:
    ds = controller.GetSearchResults(this.txtSearch.Text());
    this.dg.DataSource = ds;
    this.dg.DataBind();
    This is a trivial example, but it seems like the controller is losing control in the 2nd example and in many ways is being delegated a kind of data access layer.
    I would be interested to see how others deal with this.
    2) How much logic should go in the view? (even UI logic). For example, in order to test some of my stuff, I have started adding methods to my view interface like SetErrorMessage(string), HideDetails(), EnableSaveButton() that are called by the controller based on business logic.
    But these methods are very shallow wrappers around stuff like "this.lblError.Text = s" or "this.dgDetails.visible = false".
    It allows me to test using a mock of my view, b/c I can test that EnableSaveButton was called, meaning that it WAS enabled.
    But I am wondering if I am getting too detailed with these things and should put more of this logic in the view/UI.
    I have been using your previous HTTP simulator, so I look forward to this upgrade!
    Chris May

  6. Avatar for Ryan Smith
    Ryan Smith June 19th, 2007

    I'm looking to get into a more test driven style of development, but most the code I write is for the web.
    I find it hard to figure out the best way to approach this, but it looks like this might be a good start.
    Do you know of any good articles / sites that talk about test driven development for the web?

  7. Avatar for ISerializable - Roy Osherove's
    ISerializable - Roy Osherove's June 20th, 2007

    Phill Haack just released HTTPSimulator - a class to help with running tests against a simulated Http

  8. Avatar for Ryan Smith
    Ryan Smith June 20th, 2007

    P.S.
    You have a bug on your site:
    http://www.dynamicajax.com/...

  9. Avatar for Scruffy-Looking Cat Herder
    Scruffy-Looking Cat Herder June 20th, 2007

    Mocking Developments

  10. Avatar for Sean
    Sean June 20th, 2007

    I get an error with IConfigMapPath:
    'System.Web.Configuration.IConfigMapPath' is inaccessible due to its protection level. Have FW 2 & 3 installed and System.Web.dll included. Any ideas?

  11. Avatar for Christopher Steen
    Christopher Steen June 20th, 2007

    Silverlight on Linux Already [Via: Jesse Ezell ] VS 2008 Multi-Targeting Support [Via: ScottGu ] Model-View-Presenter...

  12. Avatar for Haacked
    Haacked June 20th, 2007

    @Sean - That's odd. It compiles on my machine, but it doesn't on our build server. I'm looking into it. Any ideas?

  13. Avatar for Haacked
    Haacked June 20th, 2007

    @Sean - It turns out that this is because the accessibility of this interface changes to Public with Vista.
    Read up on it here.

  14. Avatar for Sean
    Sean June 20th, 2007

    Could you extract that Interface and include in the zip file so it would be possible to run it on non-Vista machines? That would be really helpful. 10x

  15. Avatar for Sean
    Sean June 20th, 2007

    I was trying to extract IConfigMapPath, but this was useless as it has a member of VirtualPath type, which is (as usual) internal with a bunch of other internal utility classes. Would be more practical to supply the System.Web.dll from the .NET 3.0 Vista install? Banging my head over the wall as long as can't use your solution :(

  16. Avatar for Mark
    Mark June 20th, 2007

    You don't need to extract the interface. I had the same problem, what you do is compile a signed version of the HttpSimulator on your vista machine then reference the assembly in your unit test projects. This way, your build server does not compile the code itself. That was my work around.

  17. Avatar for Travis Illig
    Travis Illig June 20th, 2007

    The other alternative is to use TypeMock and mock the HttpContext. That works pretty well and hasn't caused me a build error yet. :)
    Of course, it does imply you're willing to go with TypeMock (which I love and highly recommend, and which there is a free "Community" version that should work just fine for this). Not everyone is as gung-ho for TypeMock as I am, but it does solve problems like this very nicely...

  18. Avatar for Jacob
    Jacob June 20th, 2007

    @Travis: I just discovered TypeMock and it's got me pretty excited. It's the first mock framework that does what I really want in a mock.

  19. Avatar for Don Demsak
    Don Demsak June 20th, 2007

    Have you tried to mock MapPath? I couldn't get that to work. Jason Bock found out the same thing when he tries to mock HttpContext: http://www.jasonbock.net/JB...

  20. Avatar for Haacked
    Haacked June 21st, 2007

    @Don Demsak - I did. In fact, I've included unit tests that demonstrate mocking MapPath.

  21. Avatar for lb
    lb June 21st, 2007

    this is how I mock HttpContext:
    "Oooo, Mr Context, aren't we clever! THink we're Mr Big Boots because we know so much! Well shut up, context, you ain't no einstein!"
    I find it fairly effective.
    What am I missing?
    Obligatory serious comment:
    Check out http://www.incisif.net/Quic... -- a way of writing simple unit tests as attributes of your functions/classes/properties. much fun.
    lb

  22. Avatar for Travis Illig
    Travis Illig June 21st, 2007

    Mocking MapPath is no problem with TypeMock. (Again, maybe not your cup of tea, but it does mock pretty much anything with the exception of a few of the System objects.)

  23. Avatar for Haacked
    Haacked June 21st, 2007

    Well I've heard it's free for community and OSS use, so I may give it a try. A
    t this point, I'm just hesitant to find out whether I wasted a lot of time on my impl and should just kick myself for not using it earlier. ;)

  24. Avatar for Joshua Flanagan
    Joshua Flanagan June 23rd, 2007

    Does it work with System.Web.HostingEnvironment? It was introduced in ASP.NET 2.0 and is supposed to replace a lot of the old uses of HttpContext. Apparently it is a better idea to use this class where you can, so your code is less HTTP specific (keeping in mind the new hosting models available in Vista/Server 2008/WAS).
    Clemens Vasters gave us a heads up about it on the Dasblog mailing list.

  25. Avatar for Haacked
    Haacked June 23rd, 2007

    @Joshua - How do you do this with the HostingEnvironment?
    HttpContext.Current.Request.RawUrl

  26. Avatar for Jim Bonnie
    Jim Bonnie June 27th, 2007

    Very nice - thanks for the support of session variables - I am starting to use this for Unit testing DotNetNuke Web applications.

  27. Avatar for donkeymaster
    donkeymaster June 28th, 2007

    i've been using the server from www.neokernel.com to test my ASP.Net pages (and run my website), although it IS a webserver, it runs ASP.NET like IIS does (unlike Webdev.webserver, which sometimes behaves differently).

  28. Avatar for Miguel Madero
    Miguel Madero July 16th, 2007

    Thanks man, this saved the day!!!!
    I heard some guys are having troubles, but I needed to try a really simple stuff and this just did the trick.

  29. Avatar for Paraesthesia
    Paraesthesia August 2nd, 2007

    Mock a Page Request Lifecycle with TypeMock

  30. Avatar for Dave Donaldson
    Dave Donaldson August 8th, 2007

    Adding this comment for future reference... for anyone experiencing the "System.Web.Configuration.IConfigMapPath is inaccessible due to its protection level" problem, the ConfigMapPath class is really only needed if you require programmatic access to the MapPath property within a unit test. If you don't, then comment out the internal ConfigMapPath class and the line that calls it (both in HttpSimulator.cs) and recompile. That gets it to work on your non-Vista dev machine and non-Vista build machine. At least that's how I fixed it anyway.

  31. Avatar for you've been HAACKED
    you've been HAACKED August 19th, 2007

    Why Duck Typing Matters To C# Developers

  32. Avatar for Ulu
    Ulu August 25th, 2007

    My recipe is: Plasma + TypeMock. I use Plasma for in-process testing and TypeMock to get access to the HTTPContext and Page objects. So far, I haven't used it in any tests, but I've got a valid reference to my page and verified that its controls are there, and this is a big step. Finally I'm able to use the same level of abstraction that I use in my production code.
    So, I'm able to write code like this:
    System.Web.UI.Page page = GetPage("~/Default.aspx");
    System.Web.UI.WebControls.Label label = page.FindControl("Label1");
    Assert.AreEqual("Hello World", label.Text);
    The details are here http://dotfresh.blogspot.co...
    ulu

  33. Avatar for Bruce Chapman
    Bruce Chapman August 28th, 2007

    I'm getting a strange error using your code and supplying an appPath value. After calling the SimulateRequest, my system.web.httpContext.Current.Request.AppRelativeCurrentExecutionFilePath shows a value of '~h/page.aspx' where h = the last letter of the path (ie /mypath) and page.aspx is the page name.
    This causes my code to later on rewrite a url as mypathpage.aspx (the code works Ok when running in the website). The value changes to this on the call of HttpContext.Current = new HttpContext(workerRequest).
    Any ideas? It works OK with a appPath value of "/". I was looking for some string manipulation in the code that had a 1 instead of a -1 or something, but all searches == fruitless.
    /hair torn out
    -Bruce

  34. Avatar for Dirc
    Dirc October 2nd, 2007

    Excellent work!!
    Now... I have a problem trying to use Sessions between calls that I need to simulate. I need to make one call, which saves data to the Session. I then need to make another call using the same session to check stuff that happens if a session already exists.
    Is there an existing way to do this or would I need to customise the HttpSimulator?

  35. Avatar for Haacked
    Haacked October 2nd, 2007

    I think the latest version properly simulates Session.

  36. Avatar for Joe
    Joe November 6th, 2007

    This seems to fall over when using the cache object.
    In one unit test, I add an item to the cache, and in another I try to add the item again, but it already exists.
    For example when running the following tests together , one will pass and one will fail. When running them one at a time, both will pass.
    [Test]
    public void Add_Item_To_Cache()
    {
    using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest())
    {
    Assert.IsTrue(HttpContext.Current.Cache.Count == 0, "Cache should be empty");
    HttpContext.Current.Cache.Add("myKey", "myObject", null, DateTime.Now.AddHours(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Low, null);
    Assert.IsTrue(HttpContext.Current.Cache.Count == 1, "Cache should have an item");
    }
    }
    [Test]
    public void Add_Item_To_Cache_Again()
    {
    using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest())
    {
    Assert.IsTrue(HttpContext.Current.Cache.Count == 0, "Cache should be empty");
    HttpContext.Current.Cache.Add("myKey", "myObject", null, DateTime.Now.AddHours(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Low, null);
    Assert.IsTrue(HttpContext.Current.Cache.Count == 1, "Cache should have an item");
    }
    }

  37. Avatar for Kevin G
    Kevin G November 9th, 2007

    So is there no way to solve this without using Vista?
    ..works on my machine, which is XP, not the build server, so something is being done correctly on my machine (with VS 2005 installed....)
    HttpSimulator.cs(722,38): error CS0122: 'System.Web.Configuration.IConfigMapPath' is inaccessible due to its protection level

  38. Avatar for Kevin G
    Kevin G November 9th, 2007

    ah. Found the answer here:
    http://haacked.com/archive/...
    I upgraded to .net 3.5, which replaced System.Web with a newer version.

  39. Avatar for Alexey Moudrick
    Alexey Moudrick December 25th, 2007

    Could you fix or at least suggest how to fix the test?
    [Test]
    [Ignore("NotWorking")]
    public void LoadControl()
    {
    string mapPath = AppDomain.CurrentDomain.BaseDirectory;
    string controlFullPath = @"/Control.ascx";
    File.WriteAllText(mapPath + controlFullPath, @"
    <%@ control autoeventwireup=""false"" language=""c#"" %>
    <span>test</span>");
    using (HttpSimulator simulator = new HttpSimulator(@"/", mapPath))
    {
    simulator.SimulateRequest();

    System.Web.UI.Page page = new System.Web.UI.Page();
    Assert.IsNotNull(page);
    System.Web.UI.Control control = page.LoadControl(controlFullPath);
    Assert.IsNotNull(control);
    }
    }
    Also, did not you think to start a little (or even more than little) open source project on some code hosting? Community could contribute a lot of ideas, feature and testing. I can start the projest with code linked from the article as the first contribution ;)

  40. Avatar for Alexey Moudrick
    Alexey Moudrick December 25th, 2007

    This is the output of the test:
    Starting the MbUnit Test Execution
    Exploring HttpSimulator, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    MbUnit 1.0.2700.29885 Addin
    Found 1 tests
    [failure] HttpSimulatorTests.LoadControl
    TestCase 'HttpSimulatorTests.LoadControl' failed: Object reference not set to an instance of an object.
    System.NullReferenceException
    Message: Object reference not set to an instance of an object.
    Source: System.Web
    StackTrace:
    at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)
    at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath)
    at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
    at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
    at System.Web.UI.TemplateControl.LoadControl(VirtualPath virtualPath)
    at System.Web.UI.TemplateControl.LoadControl(String virtualPath)
    D:\home\rainbow\googlecode\svn\sandboxes\moudrick\trunks\extract_PortalSettingsProvider\Tests\HttpSimulator\HttpSimulatorTests.cs(330,0): at UnitTests.SUbtext.HttpSimulatorTests.LoadControl()
    [reports] generating HTML report
    TestResults: file:///C:/Documents%20and%20Settings/alexm.BDUA/Application%20Data/MbUnit/Reports/HttpSimulator.Tests.html
    0 passed, 1 failed, 0 skipped, took 3.73 seconds.

  41. Avatar for Daniel Gonzalez
    Daniel Gonzalez December 28th, 2007

    Hi Phil,
    I am finding a VERY weird issue while using your code.
    I am testing a piece of code that changes the handler once the request is simulated. But when I run my test alongside some other tests I get an Exception:
    Test.Dgg.Utilities.Web.ClientScriptHelperTester.TryRegisterClientScriptIncludeInPage_NonPageHandler_ScriptNotRegistered : System.Web.HttpException : Invalid use of SimpleWorkerRequest constructor. Application path cannot be overridden in this context. Please use SimpleWorkerRequest constructor that does not override the application path.
    But this exception does not show when I run my test in isolation (no other test running). It shows the same strange behavior both in NUnit runner (2.4.5) and TestDriven.Net (latest version).
    Of course, when I change your code so that SimulateHttpRequest calls another base constructor, my tests run fine, but yours not.
    Any clues?
    Thanks a lot
    Any clues?

  42. Avatar for Noam Elyashiv
    Noam Elyashiv January 5th, 2008

    How can make it haapend with the user object also

  43. Avatar for 分享
    分享 January 21st, 2008

    需要测试的代码分为如下几个部分:纯粹的相对简单的计算页面逻辑HTTP相关的代码数据库相关1很容易测试,2还没有尝试过,估计有麻烦;3今天找到模拟的办法了;4基本上是可以测试的,只是数据准备和清理比...

  44. Avatar for Slevdi
    Slevdi February 4th, 2008

    @joe Re: Cache object
    Just in case you didn't solve this:
    The result you get is correct. The cache remains intact for the duration of the application so you need to clear it in between tests.
    I would put a cache clearing method as a SetUp:
    (Note that you don't need to use HttpContext for the cache; HttpRuntime works fine without the simulator.)

    internal static Cache cache = HttpRuntime.Cache;
    [SetUp]
    public void SetUp()
    {
    foreach (DictionaryEntry cacheItem in cache)
    {
    cache.Remove(cacheItem.Key.ToString());
    }
    }

    Then I would refactor the tests to use the internal static cache field.

  45. Avatar for Slevdi
    Slevdi February 7th, 2008

    Phil - I am having great success so far with HttpSimulator. Thanks for it.
    Question: How do I do resources using it? E.g.:
    string key = (string) HttpContext.GetGlobalResourceObject(classKey,resourcekey);

  46. Avatar for Jai
    Jai February 11th, 2008

    Hi,
    I was successful creating a HttpContext but not HttpContext.Current.Profile since it is read-only. My application code makes use of Profile and the NUnit test fails because
    "Property or indexer 'System.Web.HttpContext.Profile' cannot be assigned to -- it is read only". Any help here?
    Thanks in advance.
    Jai

  47. Avatar for Ulu
    Ulu March 5th, 2008

    You might want to take a look at Ivonna. Doesn't need a web server, and you can test your views in an object-oriented way (not just raw html, but control values).

  48. Avatar for Josh Blanchard
    Josh Blanchard April 2nd, 2008

    Wow. This was so helpful and so easy to use. Thanks for posting!

  49. Avatar for Paul
    Paul May 1st, 2008

    Phil, You're a life-saver. Thanks! The check is in the mail! ;-)

  50. Avatar for Ameya Gholap
    Ameya Gholap May 12th, 2008

    This is awesome - worked in a first shot
    I knew something could be done about web tests - but thought of googling instead of writing something of my own - landed up here - and it worked like magic.. Thank you!
    Cool stuff.. \m/

  51. Avatar for Pennidren
    Pennidren May 15th, 2008

    Exactly what I needed and works great.
    Thanks!

  52. Avatar for Lily
    Lily July 6th, 2008

    How to simulate post xml data via http request

  53. Avatar for Tal
    Tal December 9th, 2008

    That's great! I've been hacking the web testing for years and only now I see this?!

  54. Avatar for Jarle Friestad
    Jarle Friestad December 22nd, 2009

    Sweet man. Great work. Works like a charm :-)

  55. Avatar for Ivan Pavlović
    Ivan Pavlović February 3rd, 2010

    HttpSimulator to the rescue in the right moment! I was just about to write my own when I stumbled upon this post. Thank you!

  56. Avatar for adam Mins
    adam Mins February 23rd, 2010

    I like to use this http simulatro that send http request test to any url:
    http://soft-net.net/SendHTTPTool.aspx

  57. Avatar for Brad Ford
    Brad Ford March 31st, 2010

    It appears that the download link is no long available...

  58. Avatar for Giuseppe
    Giuseppe April 7th, 2010

    yap. download doesn't work anymore :-(

  59. Avatar for Kiran
    Kiran April 13th, 2010

    Download link is broken !!

  60. Avatar for Shabbazz
    Shabbazz April 17th, 2010

    Since download link is broken, can anyone provide another link?

  61. Avatar for mgwilson74
    mgwilson74 May 4th, 2010

    I found a version of the HttpSimulator here:
    subtext.googlecode.com/.../UnitTests.Subtext/

  62. Avatar for kamote
    kamote May 26th, 2010

    Dude, download link is broken :)

  63. Avatar for Bernhard
    Bernhard June 6th, 2010

    Erm Phil.... the download link to http://haacked.com/code/HttpSimulator.zip leads to a 404. I tried http://code.haacked.com/HttpSimulator.zip as well and failed. It appears to be available on www.pudn.com/.../detail777203.html where I would have to become a VIP member to download the source. Not very happy that they are requiring registration to get to your code that you used to provide freely.

  64. Avatar for Gabriel Halsmer
    Gabriel Halsmer October 19th, 2010

    Here's the basic code you need...

    #region fake HttpContext and session
    static void InitializeSession()
    {
    var tw = new System.IO.StringWriter();
    var wr = new System.Web.Hosting.SimpleWorkerRequest("/webapp", "c:\\inetpub\\wwwroot\\webapp\\", "default.aspx", "", tw);
    HttpContext.Current = new HttpContext(wr);
    HttpContext.Current.Items.Clear();
    var session = Activator.CreateInstance(typeof(HttpSessionState), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[]{new SimpleHttpSessionState()}, null);
    HttpContext.Current.Items.Add("AspSession", session);
    }
    public class SimpleHttpSessionState : NameObjectCollectionBase, IHttpSessionState
    {
    private string sessionID = Guid.NewGuid().ToString();
    private int timeout = 30; //minutes
    private bool isNewSession = true;
    private int lcid;
    private int codePage;
    private HttpStaticObjectsCollection staticObjects = new HttpStaticObjectsCollection();
    private object syncRoot = new Object();
    public void Abandon() { BaseClear(); }
    public void Add(string name, object value) { BaseAdd(name, value); }
    public void Remove(string name) { BaseRemove(name); }
    public void RemoveAt(int index) { BaseRemoveAt(index); }
    public void Clear() { BaseClear(); }
    public void RemoveAll() { BaseClear(); } ///
    public void CopyTo(Array array, int index) { throw new NotImplementedException(); }
    public string SessionID { get { return sessionID; } } ///
    public int Timeout { get { return timeout; } set { timeout = value; } } ///
    public bool IsNewSession { get { return isNewSession; } }
    public SessionStateMode Mode { get { return SessionStateMode.InProc; } } ///
    public bool IsCookieless { get { return false; } }
    public HttpCookieMode CookieMode { get { return HttpCookieMode.UseCookies; } }
    public int LCID { get { return lcid; } set { lcid = value; } } ///
    public int CodePage { get { return codePage; } set { codePage = value; } } ///
    public HttpStaticObjectsCollection StaticObjects { get { return staticObjects; } } ///
    public object this[string name] { get { return BaseGet(name); } set { BaseSet(name, value); } } ///
    public object this[int index] { get { return BaseGet(index); } set { BaseSet(index, value); } } ///
    public object SyncRoot { get { return syncRoot; } } ///
    public bool IsSynchronized { get { return true; } } ///
    bool IHttpSessionState.IsReadOnly { get { return true; } }
    }
    #endregion

  65. Avatar for Gabriel Halsmer
    Gabriel Halsmer October 19th, 2010

    Whoops, and you may want the namespaces too..

    using System;
    using System.Collections.Specialized;
    using System.Reflection;
    using System.Web;
    using System.Web.SessionState;

  66. Avatar for Bruno
    Bruno October 27th, 2010

    Nice work, but the download link is broken.
    Can you tell me where else can I download it?

  67. Avatar for Dpdesi
    Dpdesi November 11th, 2010

    Please can you fix the download link

  68. Avatar for J S
    J S November 16th, 2010
  69. Avatar for valamas
    valamas February 1st, 2011

    Anyone know how to extend this awesome utility to support cookies?

  70. Avatar for Judy Henderson
    Judy Henderson March 29th, 2011

    Thanks a ton. I loved your criticism. I completely agree and if I had the ability to rewrite all my code to use a wrapper I would do that but as it is I don't unless we're doing a major release, yet we want unit testing coverage. This is so helpful Thank You so much!!!

  71. Avatar for Asif Ashraf
    Asif Ashraf May 31st, 2011

    hi, haack, I need quick download of that zip but the zip you gave has not ending, I mean the link is corrupt. I am having issue with HttpContext.Current so I would like to use your code.
    Summary :D The zip file link is Broken, fix that plz.
    Thanks in advance.

  72. Avatar for Tony
    Tony October 10th, 2011

    Hi Phil,
    Awesome work! I'm using this to test the event handlers in the global.asax.cs such as Application_AcquireRequestState(). Really useful! Thanks!
    P.s. The link that J_S posted works for me, but the one in your post needs updating.

  73. Avatar for Tom Lianza
    Tom Lianza April 29th, 2012

    Anyone have any good workarounds for the fact that you can't add http headers after creating the simulated request anymore?
    msdn.microsoft.com/...(v=vs.90).aspx (see comments about "PlatformNotSupported")

  74. Avatar for John Penney
    John Penney March 13th, 2013

    I've been using this splendid utility for a while now - thanks, Phil!

    I have encountered a problem attempting to do a Redirect: I'm getting a NullReferenceException.  Has anyone managed to exercise a Redirect under HttpSimulator?  I've copied this question to http://stackoverflow.com/qu... too.

  75. Avatar for Rastko Isajev
    Rastko Isajev February 6th, 2014

    I am using it. Great library. Thank you for that ! Rastko

  76. Avatar for Cindy
    Cindy February 11th, 2014

    HI,

    Thanks for the info, surely its lot useful.
    Can i know how can mock Request.Cookies using simulator?

    Thanks,
    Cindy

  77. Avatar for Fire123
    Fire123 March 1st, 2015

    pretty cool but HOW do u test the htttpcontext identity.Thats where it hurts.All other stuff matters not.

  78. Avatar for kevin hart
    kevin hart March 8th, 2015

    Wow! Congrats, Phil! I hope that with you on board, Microsoft will manage to come up with a real MVC framework, not a toy one!

  79. Avatar for Shafiq
    Shafiq August 14th, 2015

    This is so awesome. Thank you!!

  80. Avatar for Ishit Parikh
    Ishit Parikh April 15th, 2016

    Hey,

    I'm newbie to unit testing. I tried your code but didn't work for our website.

    I may have implemented it wrongly or it isn't fit for our situation.

    I wrote a simple unit test for login functionality which uses WebSecurity object to validate user, session & cookies to store data and return boolean value. Here we got return value false because of WebSecurity so we removed it and used direct DB call to validate user. Now, when storing userdata into session and cookies we got exception of null.

    So, please help us for this situation and let me know for any addition information you want.

    Thank you.

  81. Avatar for Kees van Ginkel
    Kees van Ginkel August 24th, 2016

    Very Nice. Thank you for sharing. Still usefull after all these years