I have a controller that is only built in Debug (using #if DEBUG) that I use to house some test methods that I don't want on the production server.
The problem I'm running into is that using T4MVC I get a derived class based on the controller with overloads of all the methods. As soon as I try to build in Release mode that base class and virtual action methods are no longer present and I get build errors.
Ideally I would like to be able to exclude the controller from T4MVC but I can't see a way to do that in the settings file and the answer to this question: T4MVC How to Exclude Individual Files suggests its not possible.
Anyone know of a way to do it or can think of a good work around?
Use the T4MVC Attribute on your controller
[T4MVC(false)]
public Controller ControllerToIgnore //...
Worked for my purposes (to exclude a specific controller from being generated).
From the T4MVC documentation
Consider separating your test methods and controllers into a separate project that depends on your production code. This way you would not need to have #if Debug stuff. I'm not sure what is your set up, but you can try using NonActionAttribute that is wrapped inside #if !Debug clause. So your production code would not run the methods as actions on your controllers. But this stinks with the wrong layout of the project.
Related
I am using the WebAPI Versioning package to version my API by the X-Api-Header by using the "VersionHeaderVersionedControllerSelector". I am also using the Microsoft.AspNet.WebApi.HelpPage to autogenerate documentation for the APIs.
In order for controller versionign to work, they need to be namespaced with the VersionXYZ as the suffix in the namespace so that the "VersionHeaderVersionedControllerSelector" is able to route the request to the appropriate version of the controller like so:
namespace WEBAPI.Api.Controllers.Version1
{ public class ProductsController : ApiController {} }
namespace WEBAPI.Api.Controllers.Version2
{ public class ProductsController : ApiController {} }
This works as intended but when I look at the generated help pages the ApiDescription is including the "VersionXYZ" suffix from the namespace in the ID (GETapi/Version1.Products) and RelativePath(api/Version1.Products) properties.
Ideally what I'd like to do is to have a top level help page which just the API Version numbers and drilling in would show the API the normal way i.e. The ApiDescription.ID = GETapi/Products and the ApiDescription.RelativePath = api/Products
Is there a way to achieve this using the Out of the Box APIs or am I going to need to rollout my own implementation of ApiExplorer
Check out this answer Get Help page works with Api Versioning
Make sure you have configure the versioning right, and you need to get a documentation XML file from your project XXXX.Api.v1 project and place it in the bin folder of the XXXX.Api project.
Unfortunately ApiExplorer does not support duplicate controller names. So by implementing controller versioning this way, your (or the package code) doesn't play nicely with the system.
Consider another alternative where you actually change the controller name (and yes you will have to implement your own solution, but honestly its not that complex). For example make the version be part of the controller name itself (rather than its name space).
e.g. Ver1_ProcuctsController
Now these will start showing up on your help page, and since help page is just content package you can change the logic to make the names that start with verxxx_ to mutate.
I made a settings page for my website. On this page the user is presented with a bunch of site wide settings they can manipulate. I made it so when the user selects a setting the page will automatically run an ajax request to send the setting to the database. My question is in how I do this.
At first I just did calls to the repository. One call to get the data back, put it into a ViewModel then give that ViewModel to the View and the ajax controller just sent the settings back to the database. This way seemed like the best at first especially for unit testing purposes since I could just pass in a fake repository if needed. Then for the user to get a setting they just called the repository and pass in the setting name they want.
Then I had a bright idea. I made a singleton class called SiteWideSettings and each possible setting on the site was a property of the site. When SiteSettings is called for the first time all of the settings are loaded. When Set is called on any of the properties it will call the repository function to send the setting. Now with my Settings view I'm just passing in SiteWideViewOptions.Current and on the ajax call I'm updating the property that was changed. This is working for me however it's not very unit testable since I can't really pass in a repository to a singleton's constructor since its constructor is private. What I currently have is working fine but I just don't feel like it's the best solution and unit testing isn't really possible here.
I'm thinking of one of the following but not sure which is the best.
Add a Repository property to the SiteWideSettings class
Add a function to the SiteWideSettings class to pass in a repository
Not use a singleton for this at all and just go back to what I was doing before I had this idea
Any comment on this would be greatly appreciated.
Note: I know. I know I'm doing unit testing wrong in this case because I didn't write my test first so please don't scold me for that.. I have already scolded myself and with my next task I won't do it again I promise :)
"Then I had a bright idea. I made a singleton class called
SiteWideSettings and..."
This sounds like a bad idea. Let your database be ground-truth for what the settings are, not some in-memory cache that you now need to keep up to date. Let your ORM do caching if you need it for performance otherwise you are just adding problems especially if you now try to run your site on more than one server.
If you want to simplify the controller so it has less 'set-up' and 'tear-down' code in it, use an IOC (e.g. Autofac) and inject any dependencies you need (e.g. a DataContext or a Repository) on a per-http-request basis.
Your action methods are now easier to test since you can simply instantiate your controller (injecting the dependencies manually using its constructor) and then call your method.
I currently test my CodeIgniter app with phpunit by using CIUnit (https://bitbucket.org/kenjis/my-ciunit). The problem is that I have multiple controllers with the same name. I have a controller in the root controller directory named "Blog" and I have a controller called "Blog" in the controller/ajax/ directory.
The reason is to seperate all ajax requests from the main controller.
When I am running tests on both files, I get the following error:
PHP Fatal error: Cannot redeclare class Blog in ...
Well, I am not suprised I am getting this error.
What are my options to resolve this?
Prefix controllers in ajax directory with "ajax" (looks only a bit stupid url/ajax/ajax_blog)
Use namespaces (I guess I need to namespace codeigniter too then)
Create 3 seperate phpunit.xml files
This aren't really solutions I am looking for. Do I have any other options? Is it somehow possible to run each testsuite seperatly, but still in one command? Can I "clean" objects between testsuites? Anything else?
There are no other options except those you mentioned, as it is impossible to "unload" class definitions in PHP.
Naming two controllers the same is not a problem when you run CI normally, since only one controller is instantiated per request, but something that should be avoided.
If it is just the ajax-url you don't like, maybe override it in a route (in config/routes.php):
$routes['ajax/blog'] = 'ajax/ajax_blog';
I've tried with netbeans and eclipse, with no luck... (coudn't try IntelliJ idea)
I gave a quick look ant the code
http://kickjava.com/src/groovy/servlet/TemplateServlet.java.htm
and it gives me the impression that .gsp pages are translated to .groovy servlets (groovlets) in memory (I might be wrong)...
so perhaps it's not so easy to debug gsp as I though...
so, can anybody tell me how to do it?
pd: By debugging I mean things like browsing the code step-by-step, inspecting variables, adding watches, and all those sort of things, obviously. Not the (not so) good old printf approach...
Most of the logic in your GSPs should be encapsulated in TagLibs, and you can debug them (with IntelliJ at least), just as easily as any other Groovy code.
If you do have a lot of scriptlet code in your GSPs (which you shouldn't), and you want to debug into it, you can't do much more than println. One other possibility is to view the source of the Groovy code generated for your GSP. This can be done by appending a showSource parameter to the URL, as described here.
I use a hack: add a method to any controller, like static def debugme(def param) { def a = param }, and call it from gsp code: <% ThisController.debugme(this) %>, or <% ThisController.debugme(params) %>
(you do know you don't have to restart application after editing a controller or view, right?)
I also don't think that all the logic should be in taglibs: page-specific logic should be clearly visible in a controller or a view. We have most of the logic in controllers or domain classes.
Add a setting to Config.groovy and the generated gsp-files will be written to a directory: grails.views.gsp.keepgenerateddir='/some/existing/directory'
(the target directory has to exists and be writable)
More information:
http://jira.codehaus.org/browse/GRAILS-4422
It should be possible to debug the generated groovy code with a standard Java debugger.
It was a long time ago when I did that (when I created the patch to grails) and I think I used jswat (http://code.google.com/p/jswat/) to debug gsps. I couldn't get eclipse to find the source files, but that's probably working in Spring Tool Suite Eclipse nowadays.
You have to debug groovy code step-by-step/step-into and use filters, otherwise you might lose the step point (because of closures?). That's already another story...
I am testing my routes in an mvc app. I have the following code:
using System.Web.Routing;
using MvcContrib.TestHelper;
using NUnit.Framework;
using web;
using web.Controllers;
namespace tests.web.Routes
{
[TestFixture]
public class routeTests
{
[Test]
public void Route_POSURL_MapsToPOSIndex()
{
MvcApplication.RegisterRoutes(RouteTable.Routes);
"~/POS".ShouldMapTo<POSController>(x => x.Index());
}
[Test]
public void Route_POSGetItem_MapsToPOSGetItem()
{
MvcApplication.RegisterRoutes(RouteTable.Routes);
"~/POS/GetItem/12345".ShouldMapTo<POSController>(x => x.GetItem());
}
}
}
However, the 2nd test fails stating:
System.ArgumentException: A route named 'Default' is already in the route collection. Route names must be unique.
If I run either test individually they run fine. Obviously NUnit is sharing my Routing table across tests. Why?
I know I can put my RegisterRoutes call in a TestFixtureSetup method but this doesn't answer the issue and I'd like to know what I am missing.
Am I just missing something? How come I can't find this question anywhere else on the net?
Thanks!
Matt
I don't think it's NUnit sharing the routes - I do believe that is how ASP.NET MVC works. FWIW, when testing my routes I usually put RegisterRoutes in [TestFixtureSetup]. You'd probably be okay to just do the same thing.
I found this great article from Martin Fowler which explains what is going on:
http://martinfowler.com/bliki/JunitNewInstance.html
Kudos to the xUnit Test Patterns book, as it's the one that led me to the article.
I don't know if it's because I used to be a Java guy or if I just made some assumptions. JUnit creates a new TestCase object for every single method when you run tests. That means that even global variables are reset for every single test method and are not shared.
This is not the case with NUnit. NUnit creates only one TestCase object, thus any global variables are shared. Tom, you're right in the fact that MVC creates the global variable for my routes, however, NUnit does not dump this and create a new one for each test like most other xUnit frameworks do.
I have placed the register routes code in the TestFixtureSetup method, and it works of course. I'm glad that I understand what's going on now.