I'm trying to run some tests on my MVC application but I've been experiencing a world of trouble getting it to work. I'll try to get right to the point:
I'm using RhinoMocks to try something like this:
Setup:
MockRepository mocks = new MockRepository();
HttpContextBase _mockContext = mocks.FakeHttpContext();
mocks.SetFakeControllerContext(new LoginController());
HttpApplicationStateBase appState = MockRepository.GenerateStub<HttpApplicationStateBase>();
_mockContext.Expect(mc => mc.Application).Return(appState);
HttpContext.Current = _mockContext.ApplicationInstance.Context;
Here's the FakeHttpContext() method:
public static HttpContextBase FakeHttpContext(this MockRepository mocks)
{
HttpApplication app = mocks.PartialMock<HttpApplication>();
HttpContextBase context = mocks.PartialMock<HttpContextBase>();
HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
HttpResponseBase response = mocks.PartialMock<HttpResponseBase>();
HttpSessionStateBase session = mocks.PartialMock<HttpSessionStateBase>();
HttpServerUtilityBase server = mocks.PartialMock<HttpServerUtilityBase>();
SetupResult.For(context.ApplicationInstance).Return(app);
SetupResult.For(context.Request).Return(request);
SetupResult.For(context.Response).Return(response);
SetupResult.For(context.Session).Return(session);
SetupResult.For(context.Server).Return(server);
mocks.Replay(context);
return context;
}
I really need to access HttpContextBase.Request.AppRelativeCurrentExecutionFilePath but it's always returned as null. The same goes for HttpContext.Current.Request.RequestContext.
Can anybody help me out here? It's safe to say I'm desperate at this point.
First of all, try avoid using HttpContext.Current as using a static method makes it much harder to test as you have found out now. If you are using a dependency injection framework, inject HttpContextBase into your constructor.
For your actual problem, in FakeHttpContext() try to change
HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
to
HttpRequestBase request = mocks.GenerateStub<HttpRequestBase>();
and then in your test you can do something like this:
_mockContext.Request.Stub(x=> x.AppRelativeCurrentExecutionFilePath).Return("foo");
var result = object.DoSomething();
Assert.AreEqual("foo",result);
I don't think it's quite useful to do partial mocking on the HttpContext as you will be testing the framework instead (i.e. test that the framework returns you the correct value X based on value Y and Z in the HttpContext)
Another alternative is to create a wrapper class around HttpContextBase that will return you computed values. E.g. HttpContextBaseWrapper.AppRelativeCurrentExecutionFilePath(), HttpContextBaseWrapper.RequestIpAddress(). This will make testing ALL your other classes less complicated as they do not have to worry about mocking HttpContextBase and the details, they simply have to mock your HttpContextBaseWrapper class.
Edit:
I'd also recommend you to inject your HttpRequestContext as well, but if that's not possible then you can stub the RequestContext like so in the FakeHttpContext method:
var requestContext = MockRepository.GenerateStub<RequestContext>();
request.RequestContext = requestContext;
Why don't you make an abstraction class which contains calls to the HttpContext base?
Then you can do something like this:
public class MyClass
{
private readonly IHttpContext _httpContext;
MyClass(IHttpContext httpContext)
{
_httpContext = httpContext;
}
public void Blaat()
{
_httpContext.DoYourThingsWithTheHttpContext();
}
}
Assuming you are using dependency injection, otherwise look at the Fakes and Stubs framework from Microsoft.
Related
I'm building a Web API in ASP.NET Core, and I want to unit test the controllers.
I inject an interface for data access, that I can easily mock. But the controller has to check the headers in the Request for a token, and that Request doesn't seem to exist when I simply instantiate the controller myself, and it is also get-only, so I can't even manually set it. I found lots of examples to mock an ApiController, but that isn't .NET core. Also many tutorials and examples of how to unit test .net core controllers, but none actually used the HttpRequest.
I built an MCVE to demonstrate this:
[Produces("application/json")]
[Route("api/Players")]
public class PlayersController : Controller
{
private IAccessor accessor;
public PlayersController(IAccessor ac = null):base()
{
accessor = ac ?? AccessorFactory.GetAccessor();
}
/// <summary>
/// Get all players. Must be logged in.
/// </summary>
/// <returns>Ok or Unauthorized.</returns>
[HttpGet]
public IActionResult Get()
{
Player client = accessor.GetLoggedInPlayer(Request.Headers["token"]); // NRE here because Request is null
if (client == null) return Unauthorized();
return Ok(accessor.GetAllPlayers());
}
}
I'm using Moq and MSTest in my test project, and inject a mocked IAccessor. How do I inject the Request, or initialize it with the controller? I guess my last resort would be reflection, but I really want to avoid that.
When creating an instance of the controller under test, make sure to assign a HttpContext that contains the required dependencies for the test to be exercised to completion.
You could try mocking a HttpContext and providing that to the controller or just use DefaultHttpContext provided by the framework
//Arrange
var mockedAccessor = new Mock<IAccessor>();
//...setup mockedAccessor behavior
//...
var httpContext = new DefaultHttpContext(); // or mock a `HttpContext`
httpContext.Request.Headers["token"] = "fake_token_here"; //Set header
//Controller needs a controller context
var controllerContext = new ControllerContext() {
HttpContext = httpContext,
};
//assign context to controller
var controller = new PlayersController (mockedAccessor.Object){
ControllerContext = controllerContext,
};
//Act
var result = controller.Get();
//...
The above assumes you already know how to mock the controller dependencies like IAccessor and was meant to demonstrate how to provide framework specific dependencies needed for the test.
I'm building a Web API in ASP.NET Core, and I want to unit test the controllers.
I inject an interface for data access, that I can easily mock. But the controller has to check the headers in the Request for a token, and that Request doesn't seem to exist when I simply instantiate the controller myself, and it is also get-only, so I can't even manually set it. I found lots of examples to mock an ApiController, but that isn't .NET core. Also many tutorials and examples of how to unit test .net core controllers, but none actually used the HttpRequest.
I built an MCVE to demonstrate this:
[Produces("application/json")]
[Route("api/Players")]
public class PlayersController : Controller
{
private IAccessor accessor;
public PlayersController(IAccessor ac = null):base()
{
accessor = ac ?? AccessorFactory.GetAccessor();
}
/// <summary>
/// Get all players. Must be logged in.
/// </summary>
/// <returns>Ok or Unauthorized.</returns>
[HttpGet]
public IActionResult Get()
{
Player client = accessor.GetLoggedInPlayer(Request.Headers["token"]); // NRE here because Request is null
if (client == null) return Unauthorized();
return Ok(accessor.GetAllPlayers());
}
}
I'm using Moq and MSTest in my test project, and inject a mocked IAccessor. How do I inject the Request, or initialize it with the controller? I guess my last resort would be reflection, but I really want to avoid that.
When creating an instance of the controller under test, make sure to assign a HttpContext that contains the required dependencies for the test to be exercised to completion.
You could try mocking a HttpContext and providing that to the controller or just use DefaultHttpContext provided by the framework
//Arrange
var mockedAccessor = new Mock<IAccessor>();
//...setup mockedAccessor behavior
//...
var httpContext = new DefaultHttpContext(); // or mock a `HttpContext`
httpContext.Request.Headers["token"] = "fake_token_here"; //Set header
//Controller needs a controller context
var controllerContext = new ControllerContext() {
HttpContext = httpContext,
};
//assign context to controller
var controller = new PlayersController (mockedAccessor.Object){
ControllerContext = controllerContext,
};
//Act
var result = controller.Get();
//...
The above assumes you already know how to mock the controller dependencies like IAccessor and was meant to demonstrate how to provide framework specific dependencies needed for the test.
I'm currently writing unit test for my project where I'm using HttpContext.Current.User.Identity.Name at a defined time. Unfortunately, I can't make the test work since HttpContext is null when I run the test.
I already tried some solution I found on internet like Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("rmllcc"), new string[0]); but I can't get it work.
I'm using a Forms Authenticate system, xUnit with Moq. I'm not testing a controller but a Repository where I'm just logguing each time a user make use of a particular method. How could I accomplish this?
Listen to what your tests are telling you: use the fact that this test is hard to write to think about the structure of your code. You have introduced a dependency in your repository layer to the web application. That's not good. You also have two things going on in your repository: data access and logging.
Maybe wrap the current user in an abstraction that will get the user you need, but can be easily stubbed. Or you could wrap the repository in a decorator that does the logging for you.
Sorry this is not a direct answer to the question but, when tests are hard to write, there is usually a deeper underlying reason that you need to address.
I suggest you dont use the HttpContext from the repository, Make a own context class or a Interface wrapping the user-property.
Something like this:
public class MyContext
{
public MyContext(string username)
{
Username = username;
}
public string Username { get; private set; }
public static MyContext CreateFromHttpContext(HttpContext httpContext){
return new MyContext(HttpContext.Current.User.Identity.Name);
}
}
public class MyRep
{
private readonly VtContext _context;
public MyRep(MyContext context)
{
_context = context;
}
... other repository code...
}
then just create a MyContext in your test:
var rep = new MyRep(new MyContext("unittest"));
Im trying to write some unit tests for a couple of merthods that are dependant on the HttpContext object. I have come up with the following class but I dont think its the best way to do it.
internal class HttpContextMocking
{
public static HttpContext Context()
{
HttpContext context = new HttpContext(new SimpleWorkerRequest("", "", "", null, new StringWriter()));
context.Cache.Insert("SomeName", "value", null, DateTime.Now.AddMinutes(3), TimeSpan.Zero);
return context;
}
I then call this mock HttpContext in my unit test in the following way:
[TestMethod]
[TestCategory("Web")]
public void Get()
{
HttpContext.Current = HttpContextMocking.Context();
object result = CacheUtility.Get("NonExistentItem");
Assert.IsNull(result);
}
is there a better way of implementing this, something that would be cleaner when I start to add more dummy data.
HttpContext is really complex to mock. I will suggest to change the dependency to an interface that provides what you need, and then have two implementations: a real one, using HttpContext and a Mock one for the tests.
If you anyway want to mock it and your code does the trick, leave it that way.
Another option is to use the ASP.NET host type for MSTest. In this case, you will be performing an actual request and your HttpContext will be there:
[TestMethod]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost(#"$(SolutionDir)\Tests", "/")]
[UrlToTest("http://localhost:1234/TestPage.aspx")]
public void MyTest()
{
Page page = testContextInstance.RequestedPage;
...
}
The HttpContextWrapper and HttpContextBase .NET classes were created for mocking purposes e.g. http://www.codemerlin.com/2011/07/mocking-httpcontext-httpresponse-httprequest-httpsessionstate-etc-in-asp-net/
Consider a method in a .NET assembly:
public static string GetSecurityContextUserName()
{
//extract the username from request
string sUser = HttpContext.Current.User.Identity.Name;
//everything after the domain
sUser = sUser.Substring(sUser.IndexOf("\\") + 1).ToLower();
return sUser;
}
I'd like to call this method from a unit test using the Moq framework. This assembly is part of a webforms solution. The unit test looks like this, but I am missing the Moq code.
//arrange
string ADAccount = "BUGSBUNNY";
string fullADName = "LOONEYTUNES\BUGSBUNNY";
//act
//need to mock up the HttpContext here somehow -- using Moq.
string foundUserName = MyIdentityBL.GetSecurityContextUserName();
//assert
Assert.AreEqual(foundUserName, ADAccount, true, "Should have been the same User Identity.");
Question:
How can I use Moq to arrange a fake HttpContext object with some value like 'MyDomain\MyUser'?
How do I associate that fake with my call into my static method at MyIdentityBL.GetSecurityContextUserName()?
Do you have any suggestions on how to improve this code/architecture?
Webforms is notoriously untestable for this exact reason - a lot of code can rely on static classes in the asp.net pipeline.
In order to test this with Moq, you need to refactor your GetSecurityContextUserName() method to use dependency injection with an HttpContextBase object.
HttpContextWrapper resides in System.Web.Abstractions, which ships with .Net 3.5. It is a wrapper for the HttpContext class, and extends HttpContextBase, and you can construct an HttpContextWrapper just like this:
var wrapper = new HttpContextWrapper(HttpContext.Current);
Even better, you can mock an HttpContextBase and set up your expectations on it using Moq. Including the logged in user, etc.
var mockContext = new Mock<HttpContextBase>();
With this in place, you can call GetSecurityContextUserName(mockContext.Object), and your application is much less coupled to the static WebForms HttpContext. If you're going to be doing a lot of tests that rely on a mocked context, I highly suggest taking a look at Scott Hanselman's MvcMockHelpers class, which has a version for use with Moq. It conveniently handles a lot of the setup necessary. And despite the name, you don't need to be doing it with MVC - I use it successfully with webforms apps when I can refactor them to use HttpContextBase.
In general for ASP.NET unit testing, rather than accessing HttpContext.Current you should have a property of type HttpContextBase whose value is set by dependency injection (such as in the answer provided by Womp).
However, for testing security related functions I would recommend using Thread.CurrentThread.Principal (instead of HttpContext.Current.User). Using Thread.CurrentThread has the advantage of also being reusable outside a web context (and works the same in a web context because the ASP.NET framework always sets both values the same).
To then test Thread.CurrentThread.Principal I usually use a scope class that sets the Thread.CurrentThread to a test value and then resets on dispose:
using (new UserResetScope("LOONEYTUNES\BUGSBUNNY")) {
// Put test here -- CurrentThread.Principal is reset when PrincipalScope is disposed
}
This fits well with the standard .NET security component -- where a component has a known interface (IPrincipal) and location (Thread.CurrentThread.Principal) -- and will work with any code that correctly uses/checks against Thread.CurrentThread.Principal.
A base scope class would be something like the following (adjust as necessary for things like adding roles):
class UserResetScope : IDisposable {
private IPrincipal originalUser;
public UserResetScope(string newUserName) {
originalUser = Thread.CurrentPrincipal;
var newUser = new GenericPrincipal(new GenericIdentity(newUserName), new string[0]);
Thread.CurrentPrincipal = newUser;
}
public IPrincipal OriginalUser { get { return this.originalUser; } }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
Thread.CurrentPrincipal = originalUser;
}
}
}
Another alternative is, instead of using the standard security component location, write your app to use injected security details, e.g. add an ISecurityContext property with a GetCurrentUser() method or similar, and then use that consistently throughout your application -- but if you are going to do this in the context of a web application then you might as well use the pre-built injected context, HttpContextBase.
[TestInitialize]
public void TestInit()
{
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
}
Also you can moq like below
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(p => p.HttpContext.Session["User"]).Returns(TestGetUser);
controllerContext.SetupGet(p => p.HttpContext.Request.Url).Returns(new Uri("http://web1.ml.loc"));
In ASP.NET MVC Core I use the following code to test controllers, which depend on HttpContext:
var controller = new HomeController();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
This is a sample unit test:
[Test]
public void Test_HomeController_Index()
{
// Arrange
var controller = new HomeController();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
// Act
var result = controller.Index();
// Assert
var viewResult = result as ViewResult;
Assert.IsNotNull(viewResult);
}
Have a look at this
http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
Using httpSimulator class,You will be able to do pass a HttpContext to handler
HttpSimulator sim = new HttpSimulator("/", #"C:\intepub\?")
.SimulateRequest(new Uri("http://localhost:54331/FileHandler.ashx?
ticket=" + myticket + "&fileName=" + path));
FileHandler fh = new FileHandler();
fh.ProcessRequest(HttpContext.Current);
HttpSimulator implement what we need to get a HttpContext instance. So you don't need to use Moq here.
If you're using the CLR security model (as we do) then you'll need to use some abstracted functions to get and set the current principal if you want to allow testing, and use these whenever getting or setting the principal. Doing this allows you to get/set the principal wherever is relevant (typically on HttpContext on the web, and on the current thread elsewhere like unit tests). This would look something like:
public static IPrincipal GetCurrentPrincipal()
{
return HttpContext.Current != null ?
HttpContext.Current.User :
Thread.CurrentThread.Principal;
}
public static void SetCurrentPrincipal(IPrincipal principal)
{
if (HttpContext.Current != null) HttpContext.Current.User = principal'
Thread.CurrentThread.Principal = principal;
}
If you use a custom principal then these can be fairly nicely integrated into its interface, for example below Current would call GetCurrentPrincipal and SetAsCurrent would call SetCurrentPrincipal.
public class MyCustomPrincipal : IPrincipal
{
public MyCustomPrincipal Current { get; }
public bool HasCurrent { get; }
public void SetAsCurrent();
}
This is not really related in using Moq for unit testing of what you need.
Generally we at work have a layered architecture, where the code on the presentation layer is really just for arranging things for being displayed on the UI. This kind of code is not covered with unit tests. All the rest of the logic resides on the business layer, which doesn't have to have any dependency on the presentation layer (i.e. UI specific references such as the HttpContext) since the UI may also be a WinForms application and not necessarily a web application.
In this way you can avoid to mess around with Mock frameworks, trying to simulate HttpRequests etc...although often it may still be necessary.