Moq: unit testing a method relying on HttpContext - c#

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.

Related

NullReferenceException in unit test result

I've just started programming in C# Webforms (previous experience in VB Webforms) and I am producing a web app that will be a small part of a bigger project.
I have created 3 separate projects, one for the webforms, one for the class library and one for the tests.
I have added all the projects into one solution and added appropriate references, Both the Webforms and Tests projects reference the class library.
I have a class in the class library that finds the username of the logged in user:
public class LoggedInUser
{
public string UserName
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
In the page load event of one of my pages, I use this class to set the text property of a literal to display the name on the screen.
protected void Page_Load(object sender, EventArgs e)
{
LoggedInUser CurrentUser = new LoggedInUser();
LitUser.Text = string.Format(" {0}", CurrentUser.UserName);
}
This works fine.
To be complete I thought I would write a unit test to make sure the logged in username is what I expected.
[TestMethod]
public void Test_Logged_In_User_Name()
{
LoggedInUser actualUser = new LoggedInUser();
string expectedUserName = "myUserName";
string actualUserName = actualUser.UserName;
Assert.AreEqual(expectedUserName, actualUserName);
}
When I run the test it throws the following exception:
System.NullReferenceException: Object reference not set to an instance of an object
on this line:
get { return HttpContext.Current.User.Identity.Name; }
Any thoughts would as always be greatly appreciated.
You'll need to create a wrapper class for HttpContext that abstracts the functionality you need. The reason for this is that HttpContext only exists for web requests and as you are running your unit tests from an application HttpContext will not exist.
Additionally any 3rd party dependency should have a wrapper created for it to assist with testing.
It's worth noting, you also shouldn't need this test at all. In this instance you are testing a 3rd parties code, something you are relying on to be accurate. The purpose of unit tests is to test your own code/logic and if you wrote tests for every 3rd party method you'd never get a product released :).
As for creating a wrapper class, they are not dissimilar from ordinary classes. You'd need to create an interface for the HttpContext class and then create a wrapper something like the below:
public class HttpContextWrapper
{
private readonly IHttpContext _httpContext;
public HttpContextWrapper()
{
_httpContext = HttpContext.Current;
}
public HttpContextWrapper(IHttpContext injectedContext)
{
_httpContext = injectedContext;
}
public string GetName()
{
_httpContext.Current.User.Identity.Name;
}
}
You could then inject a fake implimentation of HttpContext to get your desired results.
Actually, you don't necessarily need to wrap and mock the HttpContext. In your test setup, you can do something similar to the following:
var sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
HttpContext.Current = new HttpContext(
new HttpRequest("path", "http://dummy", ""),
new HttpResponse(writer)
)
{
User = new WindowsPrincipal(WindowsIdentity.GetCurrent())
};
In this example, I assign a windows principal with the identity of the current user, but in your scenario you may want to assign a specifically crafted principal, e.g. a ClaimsPrincipal or a fake implementation (or a mock).

Using Methods not Defined in Interface on Fakes within Unit Tests

In my ViewModel, portions of functionality are enabled/disabled depending on the logged-in individual's permissions. The ViewModel relies on a dependency-injected ISecurity object to check if a user has a specific permission. Different portions of functionality require different permissions.
public Interface ISecurity
{
bool UserHasPermision(int userId, string permission);
}
In my production code, the concrete implementation of ISecurity interacts with an external application which does not allow me to change an individual's permissions. I created a FakeSecurity class that would allow me to do this in unit tests.
class FakeSecurity: ISecurity
{
private Dictionary<int, List<string>> permissions = new Dictionary<int, List<string>>();
public bool UserHasPermission(int userId, string permission)
{
return permissions.ContainsKey(userId) &&
permissions[userId].Contains(permission);
}
//Not defined in ISecurity
public void SetPermission(int userId, string permission, bool hasPermission)
{
if (!permissions.ContainsKey(userId))
{
permissions[userId] = new List<string>();
}
List<string> userPermissions = permissions[userId];
if (hasPermission)
{
userPermissions.Add(permission);
}
else
{
userPermissions.Remove(permission);
}
}
}
The problem here is that SetPermission() is not defined in the ISecurity interface, so in order for my Unit Tests to set an individual's permissions I need to cast the ISecurity object registered with my IUnityContainer to a FakeSecurity object. I am told that my unit test should be ignorant of the specific type of implementation that is being used for a particular interface and that calling methods that are not defined in the interface is an anti-pattern.
[TestMethod]
public void UserDoesNotHavePermission()
{
// test setup
IUnityContainer iocContainer = GetIocContainer();
ISecurity sec = iocContainer.Resolve<ISecurity>(); //registered singleton
(sec as FakeSecurity).SetPermission(GetCurrentUser().Id, "Save Colors", false);
var viewModel = iocContainer.Resolve<MaintainColorsViewModel>(); //per-request
// asserts
Assert.IsFalse(viewModel.CanSave);
}
[TestMethod]
public void UserHasPermission()
{
// test setup
IUnityContainer iocContainer = GetIocContainer();
ISecurity sec = iocContainer.Resolve<ISecurity>(); //registered singleton
(sec as FakeSecurity).SetPermission(GetCurrentUser().Id, "Save Colors", true);
var viewModel = iocContainer.Resolve<MaintainColorsViewModel>(); //per-request
// asserts
Assert.IsTrue(viewModel.CanSave);
}
Is this a bad practice or not? I realize that I shouldn't cast my ISecurity instace to a particular type within my application code, but is this really an issue Unit Tests?
I am told that my unit test should be ignorant of the specific type of implementation
This is incorrect. It is completely normal and good practice to let tests use both fake implementations and the class under test directly.
You however, are using the DI container in your unit tests, and that actually is bad practice. Although the use of the DI container is okay when you're writing integration tests (since you want to test components in integration with other components), using the DI library in unit tests leads to hard to read and maintain tests. With unit tests, you test code in isolation. This means that you usually create the class under test by hand, and inject the required fake dependencies to get the test running.
I would therefore expect such unit test to look like this:
public void CanSave_CurrentUserHasNoPermission_ReturnsFalse() {
// Arrange
var noPermission = new FakeSecurity { CurrentUserHasPermission = false };
var viewModel = new MaintainColorsViewModel(noPermission);
// Act
bool actualResult = viewModel.CanSave;
// Assert
Assert.IsFalse(actualResult);
}
public void CanSave_CurrentUserHasPermission_ReturnsTrue() {
// Arrange
var hasPermission = new FakeSecurity { CurrentUserHasPermission = true };
var viewModel = new MaintainColorsViewModel(hasPermission);
// Act
bool actualResult = viewModel.CanSave;
// Assert
Assert.IsTrue(actualResult);
}
public void CanSave_Always_QueriesTheSecurityForTheSaveColorsPermission() {
// Arrange
var security = new FakeSecurity();
var viewModel = new MaintainColorsViewModel(security);
// Act
bool temp = viewModel.CanSave;
// Assert
Assert.IsTrue(security.RequestedPermissions.Contains("Save Colors"));
}
There are a few things to note about this code:
Both the FakeSecurity and the MaintainColorsViewModel are created directly in the tests here; no DI library is used. This makes the tests much more readable and maintainable (and faster).
I considerably simplified the FakeSecurity class (shown below), because you want fake classes to be as simple as possible.
A third test is added to check explicitly whether the MaintainColorsViewModel requests the expected permission.
The AAA pattern (Arrange/Act/Assert) is implemented explicitly.
To allow these tests to be written the way they are, the following change has been made to the ISecurity abstraction:
interface ISecurity
{
bool UserHasPermission(string permission);
}
The userId parameter has been removed from the UserHasPermission method. The reason for this is that the ISecurity implementation will be able to find out who the current user is by itself. Allowing consumers of ISecurity to pass this parameter along only means that the API is getting more complex, there is more code to write, there's a bigger chance of programming errors, and we therefore need more supporting tests. In other words, the sole addition of this userId property forces a lot of extra production and test code to write and maintain.
Here is the simpflified FakeSecurity class:
class FakeSecurity : ISecurity
{
public bool CurrentUserHasPermission;
public List<string> RequestedPermissions = new List<string>();
public bool UserHasPermission(string permission)
{
this.RequestedPermissions.Add(permission);
return this.CurrentUserHasPermission;
}
}
The FakeSecurity class now has very little code and that makes it, just by looking at it, very easy to check for correctness. Remember, test code should be as simple as possible. Side note: replacing this class with a generated mock object, doesn't make our code easier. In most cases it will actually make our unit tests harder to read, understand and maintain.
One reason for developers to start using a DI container inside their unit tests is because the manual creation of the class under test (with all its fake dependencies) causes maintenance issues in their tests. This is true actually; if the MaintainColorsViewModel has multiple dependencies, and we would create that MaintainColorsViewModel in each test, the addition of a single dependency would cause us to change all our MaintainColorsViewModel tests. This often is a reason for developers to either use a DI container -or- revert to mocking frameworks.
This however is not a good reason to start using a DI container or mocking library. A simple refactoring can completely remove the maintenance problem; we just have to create a factory method as follows:
private static MaintainColorsViewModel CreateViewModel(params object[] dependencies) {
return new MaintainColorsViewModel(
dependencies.OfType<ISecurity>().SingleOrDefault() ?? new FakeSecurity(),
dependencies.OfType<ILogger>().SingleOrDefault() ?? new FakeLogger(),
dependencies.OfType<ITimeProvider>().SingleOrDefault() ?? new FakeTimeProvider(),
dependencies.OfType<IUserContext>().SingleOrDefault() ?? new FakeUserContext());
}
Here I assume that the MaintainColorsViewModel contains 4 dependencies (namely ISecurity, ILogger, ITimeProvider and IUserContext). The CreateViewModel factory method allows passing in all dependencies using a params array, and the method tries to get each abstraction from the array and when missing replaces it with the default fake implementation.
With this factory, we can now rewrite our tests to the following:
[TestMethod]
public void CanSave_CurrentUserHasNoPermission_ReturnsFalse()
{
// Arrange
var noPermission = new FakeSecurity { CurrentUserHasPermission = false };
MaintainColorsViewModel viewModel = CreateViewModel(noPermission);
// Act
bool actualResult = viewModel.CanSave;
// Assert
Assert.IsFalse(actualResult);
}
Or we can pass in multiple dependencies if the test requires this:
[TestMethod]
public void CanSave_CurrentUserHasNoPermission_LogsWarning()
{
// Arrange
var logger = new FakeLogger();
var noPermission = new FakeSecurity { CurrentUserHasPermission = false };
MaintainColorsViewModel viewModel = CreateViewModel(logger, noPermission);
// Act
bool temp = viewModel.CanSave;
// Assert
Assert.IsTrue(logger.Entries.Any());
}
Do note that this test is just here for educational purposes. I don't suggest the view model to actually do the logging; that should not be its responsibility.
The moral of the story here is actually that good design can simplify your testing efforts considerably to the point that you can write less code and less tests, while improving the quality of your software.
You shouldn't use a DI container in unit tests, see the answer in this question.
In unit tests, the object graph that you are testing is usually small (usually a single class). So you don't need a DI container.
Without a container, here is how your test would look like:
//Arrange
FakeSecurity fake_security = new FakeSecurity();
fake_security.SetPermission(GetCurrentUser().Id, "Save Colors", false);
MaintainColorsViewModel sut = new MaintainColorsViewModel(fake_security);
//Act
...
Please note that I am assuming that you are using constructor injection to inject ISecurity into MaintainColorsViewModel.
Please note that instead of creating a FakeSecurity class, you can use auto-generated mocks by using mocking frameworks. Here is a link to one of the mocking frameworks called FakeItEasy.
Based on my experience, when you feel something not natural in Unit Test, you may want to re-factor your code.
According to this code, there are a couple choices.
Define the permission dictionary as a property in the interface. So it is easy to set values at unit testing.
Define a permission layer, IPermission, to add/retrieve/remove permission. Then you can mock IPermission in unit testing your Security implementation.
At least I would define the SetPermission method in ISecurity, your current code does not let you define an ISecurity object and let you set permission. Think the following code.
{
ISecurity sec = CreateSecurity()
sec.SetPermission() // ERROR, SetPermission is not a method in ISecurity.
}
private ISecurity CreateSecurity()
{
return new Security()
}
However, I am not sure how to unit test in this case on top of my head.

How to unit test web service with Linq

I have a web service, which I would like to do some unit testing on, however I am not sure how I can do this. Can anyone give any suggestions? Below is the webservice, it produces an object with three fields, but only when there is values in the database queue.
[WebMethod]
public CommandMessages GetDataLINQ()
{
CommandMessages result;
using (var dc = new TestProjectLinqSQLDataContext())
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
You don't need to consume your data over the WebService to Unit test it. You can just create another project in your solution with a reference to your WebService project and call directly the methods.
First up, what you've posted can't really be Unit Tested at all; by definition, a Unit Test can have only a single reason to fail; However in your case, a single test of GetDataLINQ() (the "System Under Test" or "SUT") could fail because of a problem with any of the dependencies in the function - namely, TestProjectLinqSQLDataContext and usp_dequeueTestProject.
When you call this method from a Unit test, these dependencies at present are probably beyond your control because you didn't directly create them - they are most likely created in your page classes' constructor. (Note: this is an assumption on my part, and I could be wrong)
Also, because these dependencies are at present real "live" objects, which have hard dependencies on an actual database being present, it means your tests aren't able to run independently, which is another requirement for a Unit Test.
(I'll assume your page's class file is "MyPageClass" from now on, and I will pretend it's not a web page code-behind or asmx code-behind; because as other posters have pointed out, this only matters in the context of accessing the code via HTTP which we're not doing here)
var sut = new MyPageClass(); //sut now contains a DataContext over which the Test Method has no control.
var result = sut.GetDataLINQ(); //who know what might happen?
Consider some possible reasons for failure in this method when you call sut.GetDataLINQ():
new TestProjectLinqSQLDataContext() results in an exception because of a fault in TestProjectLinqSQLDataContext's constructor
dc.usp_dequeueTestProject() results in an exception because the database connection fails, or because the stored procedure has changed, or doesn't exist.
command.Select(...) results in an exception because of some as of yet unknown defect in the CommandMessage constructor
Probably many more reasons (i.e failure to perform correctly as opposed to an exception being thrown)
Because of the multiple ways to fail, you can't quickly and reliably tell what went wrong (certainly your test runner will indicate what type of exception threw, but that requires you to at least read the stack trace - you shouldn't need to do this for a Unit Test)
So, in order to do this you need to be able to setup your SUT - in this case, the GetDataLINQ function - such that any and all dependencies are fully under the control of the test method.
So if you really want to Unit Test this, you'll have to make some adjustments to your code. I'll outline the ideal scenario and then one alternative (of many) if you can't for whatever reason implement this. No error checking included in the code below, nor is it compiled so please forgive any typos, etc.
Ideal scenario
Abstract the dependencies, and inject them into the constructor.
Note that this ideal scenario will require you to introduce an IOC framework (Ninject, AutoFAC, Unity, Windsor, etc) into your project. It also requires a Mocking framework (Moq, etc).
1. Create an interface IDataRepository, which contains a method DequeueTestProject
public interface IDataRepository
{
public CommandMessages DequeueTestProject();
}
2. Declare IDataRepository as a dependency of MyPageClass
public class MyPageClass
{
readonly IDataRepository _repository;
public MyPageClass(IDataRepository repository)
{
_repository=repository;
}
}
3. Create an actual implementation of IDataRepository, which will be used in "real life" but not in your Unit Tests
public class RealDataRepository: IDataRepository
{
readonly MyProjectDataContext _dc;
public RealDataRepository()
{
_dc = new MyProjectDataContext(); //or however you do it.
}
public CommandMessages DequeueTestProject()
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
This is where you will need to involve your IOC framework such that it can inject the correct IDataRepository (i.e RealDataRepository) whenever your MyPageClass is instantiated by the ASP.NET framework
4. Recode your GetDataLINQ() method to use the _repository member
public CommandMessages GetDataLINQ()
{
CommandMessages result;
return _repository.DequeueTestProject();
}
So what has this bought us? Well, consider now how you can test against the following specification for GetDataLINQ:
Must always invoke DequeueTestProject
Must return NULL if there is no data in the database
Must return a valid CommandMessages instance if there is data in the database.
Test 1 - Must always invoke DequeueTestProject
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to just return null; we don't care about the return value for now
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
//create the SUT, passing in the fake repository
var sut = new MyPageClass(repo.Object);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
repo.Verify(r=>r.DequeueTestProject(),Times.Once);
}
Test 2 - Must return NULL if there is no data in the database
public void GetDataLINQ_ReturnsNULLIfDatabaseEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNull(actual);
}
Test 3 - Must return a valid CommandMessages instance if there is data in the database.
public void GetDataLINQ_ReturnsNCommandMessagesIfDatabaseNotEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(new CommandMessages("fake","fake","fake");
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNotNull(actual);
}
Because we can Mock the IDataRepository interface, therfore we can completely control how it behaves.
We could even make it throw an exception, if we needed to test how GetDataLINQ responds to unforseen results.
This is the real benefit of abstracting your dependencies when it comes to Unit Testing (not to mention, it reduces coupling in your system because dependencies are not tied to a particular concrete type).
Not Quite ideal method
Introducing an IOC framework into your project may be a non-runner, so here is one alternative which is a compromise. There are other ways as well, this is just the first that sprang to mind.
Create the IDataRepository interface
Create the RealDataRepository class
Create other implementations of IDataRepository, which mimic the behaviour we created on the fly in the previous example. These are called stubs, and basically they are just classes with a single, predefined behaviour that never changes. This makes then ideal for testing, because you always know what will happen when you invoke them.
public class FakeEmptyDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return null;}
//CallCount tracks if the method was invoked.
public int CallCount{get;private set;}
}
public class FakeFilledDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return new CommandMessages("","","");}
public int CallCount{get;private set;}
}
Now modify the MyPageClass as per the first method, except do not declare IDataRepository on the constructor, instead do this:
public class MyPageClass
{
private IDataRepository _repository; //not read-only
public MyPageClass()
{
_repository = new RealDataRepository();
}
//here is the compromise; this method also returns the original repository so you can restore it if for some reason you need to during a test method.
public IDataRepository SetTestRepo(IDataRepository testRepo)
{
_repository = testRepo;
}
}
And finally, modify your unit tests to use FakeEmptyDatabaseRepository or FakeFilledDatabaseRepository as appropriate:
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new FakeFilledDatabaseRepository();
var sut = new MyPageClass();
//stick in the stub:
sut.SetTestRepo(repo);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
var expected=1;
Assert.AreEqual(expected,repo.CallCount);
}
Note that this second scenario is not an ivory-tower-ideal scenario and doesn't lead to strictly pure Unit tests (i.e if there were a defect in FakeEmptyDatabaseRepository your test could also fail) but it's a pretty good compromise; however if possible strive to achieve the first scenario as it leads to all kinds of other benefits and gets you one step closer to truly SOLID code.
Hope that helps.
I would change your Code as follows:
public class MyRepository
{
public CommandMessage DeQueueTestProject()
{
using (var dc = new TestProjectLinqSQLDataContext())
{
var results = dc.usp_dequeueTestProject().Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return results;
}
}
}
Then code your Web Method as:
[WebMethod]
public CommandMessages GetDataLINQ()
{
MyRepository db = new MyRepository();
return db.DeQueueTestProject();
}
Then Code your Unit Test:
[Test]
public void Test_MyRepository_DeQueueTestProject()
{
// Add your unit test using MyRepository
var r = new MyRepository();
var commandMessage = r.DeQueueTestProject();
Assert.AreEqual(commandMessage, new CommandMessage("What you want to compare"));
}
This allows your code to be reusable and is a common design pattern to have Data Repositories. You can now use your Repository Library everywhere you need it and test it in only one place and it should be good everywhere you use it. This way you don't have to worry about complicated tests calling WCF Services. This is a good way of testing Web Methods.
This is just a short explanation and can be improved much more, but this gets you in the right direction in building your Web Services.

How to mock or fake HttpApplication / HttpContext for testing

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.

Unit Testing Webform HttpContext Dependent code?

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/

Categories

Resources