First of all, I am aware that this question is dangerously close to:
How to MapPath in a unit test in C#
I'm hoping however, that it has a different solution. My issue follows:
In my code I have an object that needs to be validated. I am creating unit tests for each validation method to make sure it is validating correctly. I am creating mock data and loading it into the object, then validating it. The problem is that within the validation, when an error occurs, an error code is assigned. This error code is used to gather information about the error from an xml file using Server.MapPath. However, when trying to get the xml file, an exception is thrown meaning the file cannot be found.
Since MapPath is in my validation code, and not my unit test, how do I get my unit test to recognize the path? Does this question make sense?
Error Line (In my Validation code NOT my unit test):
XDocument xdoc = XDocument.Load(HttpContext.Current.Server.MapPath("App_Data/ErrorCodes.xml"));
Simplified: The Unit Test calls a method in my program that calls Server.MapPath which then fails.
I would abstract out the "filename provider" into an class that simply returns a location, then you can mock it much, much easier.
public class PathProvider
{
public virtual string GetPath()
{
return HttpContext.Current.Server.MapPath("App_Data/ErrorCodes.xml");
}
}
Then, you can either use the PathProvider class directly...
PathProvider pathProvider = new PathProvider();
XDocument xdoc = XDocument.Load(pathProvider.GetPath());
Or mock it out in your tests:
PathProvider pathProvider = new MockPathProvider(); // using a mocking framework
XDocument xdoc = XDocument.Load(pathProvider.GetPath());
After some rigorous googling and some help from a colleague we came up with a simple solution already built into .net
Above the unit tests that accesses the validation process, I added:
[TestMethod()]
[HostType("ASP.NET")]
[UrlToTest("http://localhost:###/upload_file.aspx")]
[AspNetDevelopmentServerHost("Path To Web Application", "Path To Web Root")]
This works perfectly. Basically, when the test is called, it loads the URL with the specified unit test in the page load. Since it is a web site that is now calling the unit test, the validation will have access to Server.MapPath. This solution may not work for everyone, but it was perfect for this. Thanks to all you contributed.
Try using Rhino Mocks or an alternative mocking framework to Mock the httpContext (or other dependent objects)
Or you could write your own mock objects.
Or write a MapPathWrapper class, inherit from a MapPathWrapperBase class for your real environment, then in for your unit tests create a MockMapPathWrapper object.
There should be plenty of examples for mocking on SO.
Here's one I asked:
How to use Rhino Mocks to Mock an HttpContext.Application
UPDATE
I only have experience doing this with the Asp.Net MVC, with webforms I imagein it would be a lot more difficult because of the lack of an HttpContextBase class.
I would extract methods that accept your dependencies as arguments:
public void Validate(HttpContext context)
{
ValidatePath(context.Server.MapPath("App_Data/ErrorCodes.xml"));
}
public void ValidatePath(string path)
{
XDocument xdoc = XDocument.Load(path);
ValidateDocument(xdoc);
}
public void ValidateDocument(XDocument xdoc)
{
// Original code
}
You can then test the various methods independently. For example, testing how ValidatePath() handles a missing file.
Related
I want to unit Test my HTTP Handlers. I am Using XUnit framework for unit testing, My Sample Handler Code is
public class MyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
var data = context.Request.InputStream;
//Here logic read the context.Request.InputStream
//All the data will be posted to this Stream
//Calling of business logic layer Methods
}
public bool IsReusable
{
get
{
return false;
}
}
}
I am new to Unit testing and I just want to know What are the possible test cases for testing my HandleS Since the return type of handlers is Void so I am confuse how can I write the Test for Handlers...
Note : I know HttpContextBase can called using an HttpContextWrapper, I am not asking this I am just asking What are the possible test cases for HttpHandlers
Testing void methods is an interesting topic. The main way I would go about it is to mock up an HTTP Context, and pass it in as a parameter. Then, you should be asserting on the things you are setting that HTTP context to do within your method. For example Assert.Equal("text/plain", myHttpContext.Response.ContentType); However, you need to ensure that you are creating a unit test. It says you have business logic after this step. Have you inverted your dependencies? (Passed them as parameters into the method). Are you able to mock things out appropriately? Make sure the method isn't doing an actual HTTP call (if it is a unit test). In general, I recommend less void methods with side affects but in legacy it can't be avoided. To address your initial question, test cases are going to be anything you logically expect. Did I set my route correctly? Am I expecting the content to be text? Is my payload accurate? Anything you change is a potential test, but ensure you are testing to acceptance criteria. Its okay to have multiple assertions in a test if its one logical assert.
I have a couple thousand NUnit tests for a library, many of which rely on having some statically available 'request context' that is scoped to the request being served and flows across tasks. The library consumer provides an implementation to retrieve the current request context.
I need to implement something to provide this context for our NUnit test project, where the context is scoped to each individual test run; each test run should have it's own object, and I should be able to access it from anywhere during the test.
Initially, I had achieved this using TestContext.Current.Properties and storing my request context there, but with a recent NUnit update, Properties has become read-only.
Is there any replacement that I can use to achieve 'test local' data? i.e. something that's scoped to the current test run, and statically accessible.
Similar issue on github contains the following statement from NUnit developer:
However, it's not intended that you should change the properties of an
NUnit Test, because Test and its derivatives are internal and the
implementation can change. The internal classes allow it because
custom attributes may need to do it, but I recommend that tests avoid
doing it.
And such implementation change has actually happen. Before NUnit 2.6.0, TestContext had Properties bag, but since 2.6.0 it was moved to TestAdapter. You still could access it via TestContext.CurrentContext.Test.Properties however you have no guarantee that this will not change again in the future.
The cleaner way to implement such context accessor is by adding simple holder that will compare current test against the test for which current context instance was created. If those tests do not match it just creates a new context instance and remember current test.
Here is a working sample:
internal static class ContextAccessor
{
private static TestExecutionContext currentRequestTest;
private static RequestContext currentRequestContext;
public static RequestContext Current
{
get
{
var currTest = TestExecutionContext.CurrentContext;
if (currentRequestTest == currTest)
{
return currentRequestContext;
}
currentRequestContext = CreateRequestContext();
currentRequestTest = currTest;
return currentRequestContext;
}
}
public static RequestContext CreateRequestContext()
{
return new RequestContext();
}
}
RequestContext here is your context class. CreateRequestContext() is basically a factory method that creates context. You could put any logic you need for creating new context instance.
Now in the test you could just call ContextAccessor.Current:
[Test]
public void SomeTest()
{
var context1 = ContextAccessor.Current;
var context2 = ContextAccessor.Current;
Assert.AreSame(context1, context2);
}
Sample Project on GitHub
Ive written a couple of unit tests while using dependency injection and the httpClient in the .net Core 2.0 framework.
Ive been testing my controllers like this:
var result = await __client.PostAsync("api/production-line/validate-assignment-deadline", null);
But now i wanted to mock an object and after searching a bit on the internet all i could find was to do it like this:
var controller = new ProductionLineController(mockProductionLineProvider);
which is not testing the routing and on top of that i would have to create a lot of objects. so i dont want mock my object in this way.
I would like to be able to replace the service with an mock object i havent found a way to get the IServiceCollection into my unittest method.
I would like to be able to do something like this:
var mockingDate = new DateTime(date.Year, date.Month, date.Day, 12, 00, 00);
__constantsMock.Setup(x => x.GetCurrentDateTime()).Returns(mockingDate);
services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
var result = await __client.PostAsync("api/production-line/validate-assignment-deadline", null);
I hope you can help me think of ways to get to a solution that doesnt involve me having to create every object that i would inject normaly.
Thank you in advance
edit:
im indeed doing integration tests, i want to test everything but i need to be able to configure the result coming from a DateTime.Now so i made the constants class with a function to return the datetime.now and im trying to mock/stub the class/function. that way i can test multiple scenario's that could occur.
You are looking at the standard way of mocking; you create stubs for all the dependencies (you need to be able to control all of them!) and create the controller. Being able to mock the DI framework wouldn't really buy you anything; you would still need to provide all the dependencies to the class when you constructed it.
Use mocking libraries like NSubstitute to make it easier; if you feel like you have too many dependencies then I would suspect you need to refactor your design (perhaps that controller does too much).
Note that testing with actual HTTP requests is more of an integration test; you are testing the whole app instead of just one class. In that case you can set up different environments for your program and have one that will set up the injector with whatever extra mocks/test data you need.
Once you start doing something like issuing a request to an action, you're pretty much well outside of unit test territory. What you're doing here is integration testing.
As long as you're doing integration testing, you might as well use TestServer, which will actually give you a much more accurate platform for integration tests. Setting up all the dependencies manually doesn't do anything for you in ensuring that your application actually functions as it should. The full documentation is here, but basically, you just do:
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
The return of _server.CreateClient() is actually an instance of HttpClient, so your actual test code doesn't really need to change. However, now you've got a full mockup of all your services and config baked in.
The solution to my problem was as follows:
Make an extra starting class that inherits from your StartUp class
Give that class the following code:
public class UnitTestStartup : Startup
{
public static IServiceProvider ServiceProvider;
public static IServiceCollection Services;
public static Mock<IConstants> ConstantsMock;
public void ConfigureTestingServices(IServiceCollection services)
{
ServiceProvider = base.ConfigureServices(services);
Services = services;
ConstantsMock = new Mock<IConstants>();
services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
}
}
Make the ConstantsMock (the service you want to mock) available in your baseclass
Like this:
protected Mock<IConstants> __constantsMock;
__constantsMock = UnitTestStartup.ConstantsMock;
have every unit test class inherit from your baseclass
override the __constantsMock with a new object and you're done
I can't test any logoff, login, register action from AccountController with the new Microsoft Fake Framework without having this error message: System.Security.VerificationException: Operation could destabilize the runtime.
The unit test is real simple:
[TestMethod]
public void LogOff()
{
var AccountController = new AccountController();
RedirectToRouteResult RedirectToRouteResult;
//Scope the detours we're creating
using (ShimsContext.Create())
{
ShimWebSecurity.Logout = () => { };
var test = AccountController.LogOff();
RedirectToRouteResult = AccountController.LogOff() as RedirectToRouteResult;
}
Assert.IsNotNull(RedirectToRouteResult);
Assert.AreEqual("Index", RedirectToRouteResult.RouteValues["Action"]);
Assert.AreEqual("Home", RedirectToRouteResult.RouteValues["controller"]);
}
Also find this: http://social.msdn.microsoft.com/Forums/en-US/vsunittest/thread/f84962ea-a9b2-4e0d-873b-e3cf8cfb37e2 that talk about the same bug but no answer.
Thanks!
I asked the same question before VS2012 Update 1 was released (VerificationException when instantiating MVC controller during unit testing) and I got the response from a guy from Microsoft who said that they are working on it and it should be available in the next update. Well, nothing since then.
However, in order to get the result and to continue testing using Microsoft Fakes Framework, I wrapped the calls to MVC methods like those in the UrlHelper class with my own private methods that return primitive types like string and then Shim the unit test to give me a desired result. That way I never made a call to the underlying MVC infrastructure and I got the desired result. Also, you will need to remove System.Web.Mvc.Fakes reference otherwise VerificationException will keep popping up.
If you find this tedious then you should switch to a more mature unit testing framework like Moq or Rhino.
I'm just getting started with RavenDB and I like it so far. I am however stuck on how I should unit test controller actions that interact with it.
All the questions/articles I have found like this one: Unit testing RavenDb queries tell me I should use RavenDB in memory rather than mock it away but I cannot find a solid example of how this is done.
For example I have a controller action to add an employee to the database (yes, it's overly simplified but I don't want to complicate the issue)
public class EmployeesController : Controller
{
IDocumentStore _documentStore;
private IDocumentSession _session;
public EmployeesController(IDocumentStore documentStore)
{
this._documentStore = documentStore;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_session = _documentStore.OpenSession("StaffDirectory");
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (_session != null && filterContext.Exception == null) {
_session.SaveChanges();
_session.Dispose();
}
}
[HttpGet]
public ViewResult Create()
{
return View();
}
[HttpPost]
public RedirectToRouteResult Create(Employee emp)
{
ValidateModel(emp);
_session.Store(emp);
return RedirectToAction("Index");
}
How can I verify what was added to the database in a unit test? Does anyone have any examples of unit tests involving RavenDb in MVC applications?
I'm using MSTest if that matters but I'm happy to try and translate tests from other frameworks.
Thanks.
EDIT
Ok, my test initialise creates the document store that is injected into the controller constructor, but when I run my test the OnActionExecuting event doesn't run so there is no session to use and the test fails with a null reference exception.
[TestClass]
public class EmployeesControllerTests
{
IDocumentStore _store;
[TestInitialize]
public void InitialiseTest()
{
_store = new EmbeddableDocumentStore
{
RunInMemory = true
};
_store.Initialize();
}
[TestMethod]
public void CreateInsertsANewEmployeeIntoTheDocumentStore()
{
Employee newEmp = new Employee() { FirstName = "Test", Surname = "User" };
var target = new EmployeesController(_store);
ControllerUtilities.SetUpControllerContext(target, "testUser", "Test User", null);
RedirectToRouteResult actual = target.Create(newEmp);
Assert.AreEqual("Index", actual.RouteName);
// verify employee was successfully added to the database.
}
}
What am I missing? How do I get the session created to use in the test?
After you've run your unit test, just assert that there is a new doc in the database and that it has the right fields set.
var newDoc = session.Load<T>(docId)
or
var docs = session.Query<T>.Where(....).ToList();
RavenDB in-memory mode is there so that you don't have to mock it out, you just do the following:
Open a new in-memory embedded doc store (with no data)
If needed insert any data your unit test needs to run
RUN the unit test
Look at the data in the in-memory store and see if it has been updated correctly
Update If you want a full sample, take a look at how the RacoonBlog code does it, this is the code running Ayende's blog. See these 2 files:
BlogConfigBehavior.cs
RaccoonControllerTests.cs
How can I verify what was added to the database in a unit test?
You don't. We don't test such things in unit tests. This is a responsibility for integration tests, NOT unit testing.
If you want to unit test classes, which depend on some external source (like your db), mock the database access.
EDIT:
To correct some mentioned mistakes, I'll quote definition from MSDN (however all other resources agree with that):
The primary goal of unit testing is to take the smallest piece of
testable software in the application, isolate it from the remainder of
the code, and determine whether it behaves exactly as you expect.
Without mocking you are ignoring the basic principles of Unit testing - isolation and testing the smallest piece possible. Unit test need to be persistent-ignorant and shouldn't be relying on some external class. What if the db changes over time? Rewrite all tests, even though the functionality stays exactly the same?
COME ON. You can give me -1 how many times you want, but that won't make you right.
As that thread you linked to mentioned use the EmbeddableDocumentStore by embedding RavenDB.
Here's how to set that up:
http://msdn.microsoft.com/en-us/magazine/hh547101.aspx
Here's how to use the repository pattern with raven, so you can test easily:
http://novuscraft.com/blog/ravendb-and-the-repository-pattern