I'm trying to unit test a controller that stuffs data into a ViewData. All our views require similar data (Customer info which is derived from the url). So instead of putting the call into every single controller method, the original developers chose to put this ViewData stuffing into the OnActionExecuting event.
Of course, when you invoke the controller's action from a unit test, OnActionExecuting doesn't fire. (Thanks MVC Team!)
So I tried creating a custom view engine and having it stuff the customer data into the controllerContext when the view is requested. This works fine in a browser, but my viewEngine is ignored when I run this test. No amount of ViewEngines.Add(new funkyViewEngine) has any effect.
[TestMethod()]
public void LoginTest()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FunkyViewEngine());
UserController target = new UserController();
target.SetStructureMap(); <--sets us to use the test repo
target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic
var actual = target.Login();
Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
var vr = actual as ViewResult;
Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine
Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
Assert.IsTrue(vr.ViewData.Community().CanRegister);
}
Is there any hope here? How do I either 1) create a method that gets called on controller execution BOTH in the browser and the unit framework or 2) get the unit framework to invoke my view engine.
Sorry for your frustration. The reason why you are seeing OnActionExecuting not being called when you directly call your action method from the unit test is because that's not how things work in MVC.
The request gets executed via a "pipeline", which as far as this area is concerned consists of the ControllerActionInvoker. This class is responsible for:
Finding the action method
Invoking action filters' OnActionExecuting method (note: your controller class is also an action filter)
Calling the action method itself
Invoking the action filters' OnActionExecuted method
Handling the result (e.g. finding the view and rendering it)
In your unit test you are directly invoking step 3. and skipping all the other steps. In a unit test, it is your responsibility to call any setup code required for your action to work.
However, this does not mean you should now write unit tests that use the ControllerActionInvoker to execute the entire pipeline. We (the MVC team) have already verified that all the pieces work together.
Instead, you should test your specific application code. In this case, you might consider having the following unit tests:
A test that verifies that given some Url calling OnActionExecuting on your controller puts the right Customer object into ViewData
A test that verifies that given some Customer object present in ViewData your action method returns the appropriate result
My last point is that you should keep the functionality in OnActionExecuting. A custom view engine is definetely the wrong place for it.
Not an answer you're probably looking for, but I'm using a custom MvcHandler to achieve the same goal (getting customer from URL in multi-tenant app). ViewEngine doesn't sound like a good place for this kind of logic to me...
My custom handler looks more or less like this:
public class AccountMvcHandler : MvcHandler
{
public Account Account { get; private set; }
protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
return base.BeginProcessRequest(httpContext, callback, state);
}
protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
string accountName = this.RequestContext.RouteData.GetRequiredString("account");
Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName);
return base.BeginProcessRequest(httpContext, callback, state);
}
}
Related
I want to unit test a module by throwing messages at it via Event Aggregation to make sure it responds appropriately, either by setting properties appropriately, or by publishing other messages as a result. I am using Prism 6.
In my project, the infrastructure project has:
public class ImportantMessage : PubSubEvent<string>
{
}
ModuleA publishes a message like this:
eventAggregator.GetEvent<ImportantMessage>().Publish(importantString);
ModuleB receives the message like this:
eventAggregator.GetEvent<ImportantMessage>().Subscribe(HandleImportantMessage);
Here is HandleImportantMessage:
public void HandleImportantMessage(string importantString)
{
. . .
}
The ModuleB constructor is called as follows:
ModuleB(IEventAggregator EventAggregator)
This constructor is called by the Prism framework. For unit testing, I need to create an instance of ModuleB, and pass an IEventAggregator, probably a fake one created by Moq. And I want to do this in such a way that the message I publish carries importantString with it.
If I Google the phrase “unit tests with moq and event aggregation,” there are
several references, but I didn’t see how to use any of these approaches to pass “importantString” from ModuleA To ModuleB. The sample code for Prism 5 creates a fake event aggregator, but without using Moq. I don't understand how it works, and don't see how to pass a string with it.
My test code starts off something like this:
var moqEventAggregator = new Mock(IEventAggregator);
var moqImportantMessage = new Mock<ImportantMessage>();
moqEventAggregator.Setup(x => x.GetEvent<ImportantMessage>());
Some of the references I have seen apply something like .Returns(eventBeingListenedTo.Object);
to moqEventAggregator after Setup is applied.
I obviously need to apply .Setup(something) to moqImportantMessage in order to pass importantString, but I don't see exactly what yet.
What am I missing? How do I pass a string with the fake published message?
Basically you need to mock 2 things here:
The event aggregator
The event itself
Given you have the mock of the event you need to do as you said:
moqEventAggregator.Setup(x => x.GetEvent<ImportantMessage>()).Returns(moqImportantMessage);
Mocking the event itself should be like so:
Action<string> action;
moqImportantMessage.Setup(_ => _.Subscribe(It.IsAny<Action<string>>>()))
.Callback(_action =>
{
action = _action;
});
And then you can raise the subscription like so:
action("some string");
I'm about to delve into test in the PHP world and I have some questions. I have a controller which handles a loan application. The bulk of the work is then delegated to a ProcessLoanApplication class.
ApplyController
class ApplyController extends Controller
{
public function indexAction(Request $request)
{
$form = $this->createForm(new LoanApplication());
if($request->getMethod() == 'POST') {
$form->bind($request);
if($form->isValid()) {
$session = $this->getRequest()->getSession();
$loan_app_processor = new Tasks\ProcessLoanApplication($form, $session);
$loan_app_processor->process();
return $this->redirect($this->generateUrl('apply_thanks'));
}
}
Tasks\ProcessLoanApplication
class ProcessLoanApplication
{
private $_QuickBaseModels;
private $_session;
private $_app; // submitted form data
private $_existingApp = false; // holds existing application in QB, if it exists
public function __construct(Form $form, Session $session)
{
$this->_app = $form->getNormData();
$this->_session = $session;
// save the form data to a session
$session->set('application', $this->_app);
// create the quickbase table models objects
$this->_QuickBaseModels['GenFnHome\Application'] = new GenFnHome\Application();
$this->_QuickBaseModels['GenFnHome\SSN'] = new GenFnHome\SSN();
}
public function process()
{
$this->_existingApp = $this->_getExistingApplication();
$app_status = $this->_existingApp[GenFnHome\SSN::LogInApplicationStatus];
if(!$this->_existingApp || ($this->_existingApp && ($app_status !== 'PENDING' && $app_status !== 'OPEN' && $app_status !== 'EXPIRED')))
return $this->_saveNewLoanApplication();
if($app_status == 'EXPIRED') $this->_reOpenApplication();
}
There's a lot going on here, so I will outline it first:
User makes a requests for the application
Application form is validated
If valid, process loan application
Check if the user already has an app, if so - do X, if not Y
The application is persisted in an 'online database' (QuickBase) that my application communicates with via XML over HTTP (in other words, there is no real db)
My questions to the community:
What should be tested here? I know it is largely up to me, but perhaps the community can recommend some baseline tests that should def be written. Should I be testing the controller, the processor class, and the QuickBase class?
Should my tests be independent of one another - meaning, I should test each component individually, rather than have one massive testApplication that does everything the indexAction does and just looks for the expected sessions vars that get set?
Finally, how does one test API calls (request / response) without actually making real request (I'm using PHPUnit).
Anything else I should know?
Thanks!
What should be tested here? I know it is largely up to me, but perhaps the community can recommend some baseline tests that should def be written. Should I be testing the controller, the processor class, and the QuickBase class?
I recommend to test every class you build. If you are using Test Driven Development, the test declares what you are building, no test no code.
Should my tests be independent of one another - meaning, I should test each component individually, rather than have one massive testApplication that does everything the indexAction does and just looks for the expected sessions vars that get set?
Every Unit test should be isolated and should only test the Class that you are testing. You should use Mock object (use the PHPunit mock library or other 3th party libraries as Mockery) if one object dependences on another object.
Finally, how does one test API calls (request / response) without actually making real request (I'm using PHPUnit).
You can use the Symfony's WebTestCase that provides easy methods to imitate a browser request, learn more about that in the documentation. We call that Functional Testing.
This is usually the stage after Unit Testing. In Unit Testing you will test each individual class (it's a good practice to unit test your controller) and after that you write your Functional Tests which combines everything and tests if it works like expected.
for Controllers you should use functional tests (http://symfony.com/doc/2.0/book/testing.html#functional-tests). With them you can emulate browser and user's actions like submiting form and checking validation, database changes, http status codes and so on.
You should not forget to unit test ProcessLoanApplication.
I dont realy know why you pass form object to ProcessLoanApplication anyway. You should pass entity - it has normdata already.
Coders, I am in process of writing test cases for Asp.net MVC 3 project and I need call an action method that insert data into a database using Entity Framework. Here is the code for the action method:
//
// POST: /School/Create
[HttpPost]
public ActionResult Create(School school)
{
if (ModelState.IsValid)
{
db.Schools.Add(school);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(school);
}
And here is the code for my test method:
[TestMethod]
public void CreateNewSchool()
{
var schoolController = new SchoolController();
var viewResult = schoolController.Index();
//creating a school object
School school = new School();
school.Name = "OOO";
//passing the school object to the action method
schoolController.Create(school);
//making sure that the model is not null
Assert.IsNotNull(viewResult.Model);
}
Notice, however, that I don’t check if the data were actually inserted in the database. I just check that the model of the view is not null. I do manually check the database using SQL server management studio.
The problem is though that when I call the action method in the test method to create/insert a record in the database nothing happened to the database. However, if I run the application and brows to the create page and try to create a new recorded then the record will be added to the database. So it appears to me that insertion to database happens only if I run the application and actually brows to the create page and hit the create button, but I cannot programmatically call the action method in the test method to insert a new record in the database. I have also debugged the test case and it did hit the db.SaveChanges(); line in the action method, but no changes were reflected in the database.
So, can someone explain to me why I am not able to insert a record by calling the action method in my test method?
Thanks in advance.
I would look into how your db context is getting instantiated. In many cases, it is not desirable for unit tests to cause database round-trips, so people use strategies like mocking to prevent it. It might be something as simple as using a different connection string when you are running a unit test versus running it as an asp.net application.
Do you have any validation on the school class? I am guessing when you run it under the test environment that school is not valid and so ModelState.IsValid returns false and doesn't save.
I'm fairly new to unit testing and can't get around how to test (or if I even should) this case properly.
I have a controller method (pseudo code):
public ActionResult Register(formModel model)
{
if (ModelState.isValid) {
try {
_userService.CreateUser(a bunch of parameters here);
return RedirectToAction(some other action);
}
catch (Exception e)
{
ModelState.AddModelError("",e.Message);
}
}
return View();
}
I have a bunch of separate tests against "_userService". The "CreateUser" method just creates a new user and returns nothing OR throws an exception if there was an error (ex. the user exists) that I bubble up to the controller surround in a try catch and add the exception to the ModelState.
From what I understand I should mock the service and assert that it was called correctly (i use the assertwascalled syntax) since it returns nothing and I just want to know that my controller calls it.
What I'm not sure is how to test that when the userservice throws an error it should not redirect and should add that exception to the modelstate. With rhino mocks you can stub a mock but the book art of unit testing advises against that.
Right now in my test I manually add a model error (not caring if it's from user service) and test that the controller returns the same view if there are errors. Is this the correct way of going about this? Or should I maybe create a separate test where I stub the _userService to throw an error and check it gets added to modelstate? Or should I not even test that case? I feel like I may be just over analyzing the whole thing and testing using the modelstate would be enough to satisfy this...
Your mock represents a collaborating class. I wouldn't get too hung up on the difference between mocks and stubs; it's still a collaborating class.
You can think of your unit tests as describing how to use your class, and how the class then interacts with its collaborators. You have two examples:
Given a controller
When I register the model
Then the class should ask the user service to create a user.
And:
Given a controller
Given the user service is broken
When I register the model
Then the class should attach the error to the model state.
It's that second Given that tells you you're stubbing rather than mocking. You're setting the user service up as though it's broken. The context in which the class acts is different, so you need to stub, and you should indeed throw an exception.
If you put these lines as comments inside your test, it'll make sense. If it makes sense, ignore the book.
BTW, this is unit-level BDD. You can use "Given, When, Then" at a unit level just as at a scenario level, and it might help you think about the logic of your tests. Just don't use BDD scenario tools for this.
I've created a unit test that tests interactions on my ViewModel class in a Silverlight application. To be able to do this test, I'm mocking the service interface, injected to the ViewModel. I'm using Moq framework to do the mocking.
to be able to verify bounded object in the ViewModel is converted properly, I've used a callback:
[Test]
public void SaveProposal_Will_Map_Proposal_To_WebService_Parameter()
{
var vm = CreateNewCampaignViewModel();
var proposal = CreateNewProposal(1, "New Proposal");
Services.Setup(x => x.SaveProposalAsync(It.IsAny<saveProposalParam>())).Callback((saveProposalParam p) =>
{
Assert.That(p.plainProposal, Is.Not.Null);
Assert.That(p.plainProposal.POrderItem.orderItemId, Is.EqualTo(1));
Assert.That(p.plainProposal.POrderItem.orderName, Is.EqualTo("New Proposal"));
});
proposal.State = ObjectStates.Added;
vm.CurrentProposal = proposal;
vm.Save();
}
It is working fine, but if you've noticed, using this mechanism the Assert and Act part of the unit test have switched their parts (Assert comes before Acting). Is there a better way to do this, while preserving correct AAA order?
I'm not sure that you've changed the semantics of the AAA order. Consider the execution of the test. Your mocked interface will not be called until the Action invokes it. Therefore, during execution, your program still follows the Arrange, Act, and Assert flow.
The alternative would be to use Data Injection and create an interface between your CampaignViewModel and the web service that it uses. You can then create a class in your UnitTests that saves your parameter information and Assert on that class member/property rather than use Moq to create a proxy on the fly.
Moq should not be used to simulate storage or assignment. Rather, use Moq to provide dummy mechanisms and values to allow your Unit Tests to execute. If Asserting storage is a requirement, then take the time to create a class that will hold on to your values.