I'm trying to test a controller made with Symfony 4 with PHPUnit.
I'm using https://github.com/lexik/LexikJWTAuthenticationBundle to manage JWT.
This controllers should return a 200 if a valid JWT is given, a 401/403 otherwise.
The first part with the 401 response is easy: I just don't send any token
<?php
namespace App\Tests\Controller;
Class GraphQLControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase {
function test_token(){
$client = static::createClient();
$client->request('GET', '/graphql');
// Check 401 response
$response = $client->getResponse();
$this->assertSame(401, $response->getStatusCode());
$this->assertSame('"Not authenticated"', $response->getContent());
}
}
The next part is tricky: how do I get my JWT encoder service in my test_token method in order to generate some tokens to test 200 and 403 responses?
If I were in a controller I could use Symfony autowiring or make a public alias of lexik_jwt_authentication.encoder to be used like this:
$this->container->get('lexik_jwt_authentication.encoder')
Loading manually the service in my test like this bellow seems inefficient as some of the arguments of the constructor are some objects, and some arguments of their own constructor are objects, and ...
new Lexik\Bundle\JWTAuthenticationBundle\Encoder\DefaultEncoder([some objects here])
This is what is nice with autowiring: you just get the service you want ready to be used.
=> What's the best way to get this service in my test?
Thanks!
It's now possible with Symfony 4.1 to load a private service within a test using the KernelTestCase
I have my middleware and inside it I am trying to reach the current url of the page. so I did something like that:
$url = Request::url();
and I used:
use App\Http\Requests;
use Illuminate\Http\Request;
but I keep getting the following error:
Non-static method Illuminate\Http\Request::url() should not be called statically, assuming $this from incompatible context
any ideas?
You can access the url from the Request Object:
public function handle($request, Closure $next)
{
$url = $request->url();
...
}
Request object has also fullUrl() and path() methods. Choose the one that fit your needs
In Laravel 5 the request is already passed into the handle() function
class MyMiddleware {
public function handle($request, Closure $next)
{
$url = $request->url();
// Do stuff here
return $next($request);
}
}
Laravel 5 tries to move away from facades (e.g: Calls such as Request::url()) in favour of using dependency injection, so you may notice some functions and such cannot be accessed the same as you did in 4.
Heres quite a nice explanation of dependency injection in Laravel 5 https://mattstauffer.co/blog/laravel-5.0-method-injection
My web app is using PKI authentication via a piv card. I grab the user's unique identifier information via HttpClientCertificate.Subject. The problem is that when I am unit testing, mock will not mock this class since it doesn't have a constructor. I tried following the advice on this thread:
How to mock HttpClientCertificate?
but it looks like the way he sets it up is to inject the client certificate through the controller's constructor which I dont' want to do since the controller already has access to the client certificate. I'm assuming thats what he is implying since he is using some type of adapter pattern. Anyone got any better sugguestions?
Why don't you wrap it into your own object?
class MyHttpClientCertificate
{
public MyHttpClientCertificate(HttpClientCertificate foo) { ... }
internal MyHttpClientCertificate() { ... }
}
Your issue is that the code is using the Request object to get the certificate, but that's not easily unit testable.
What I would do is add a function delegate that, by default, will use the Request object to return the HttpClientCertificate, but will allow overriding the implementation.
For the controller, add this:
internal Func<HttpClientCertificate> HttpClientCertificateGetter = () => {
return Request.ClientCertificate;
}
And in your Controller instead of using Request use HttpClientCertificateGetter.
Then in your unit test you mock the certificate and assign it to the getter function, like this:
var certMock = new Mock<HttpClientCertificate>();
HttpClientCertificate clientCertificate = certMock.Object;
requestMock.Setup(b => b.ClientCertificate).Returns(clientCertificate);
certMock.Setup(b => b.Certificate).Returns(new Byte[] { });
controller.HttpClientCertificateGetter = () => {certMock.Object};
i have these methods in module1/actions/actions.class.php:
public function executeMethod1(sfWebRequest $request){
$a = 10;
sfContext::getInstance()->set('a', $a);
return $this->redirect('module1/method2');
}
public function executeMethod2(sfWebRequest $request){
echo sfContext::getInstance()->get('a');
}
When i execute module1/method1 i get this error:
"The "a" object does not exist in the current context."
Any idea?
Javi
The redirect is telling the browser to load another page which terminates the current action and results in a new request that has a new context.
There are three options here:
You could use a forward if you want module1/method2 to be executed as the result of the first request.
You could use a flash attribute to pass $a to the next request.
You could use a session attribute if $a has to live beyond the next request.
EDIT: You don't need the return statement before the redirect either.
I'm implementing a prototype of a RESTful API using ASP.NET MVC and apart from the odd bug here and there I've achieve all the requirements I set out at the start, apart from callers being able to use the X-HTTP-Method-Override custom header to override the HTTP method.
What I'd like is that the following request...
GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE
...would be dispatched to my controller method that implements the DELETE functionality rather than the GET functionality for that action (assuming that there are multiple methods implementing the action, and that they are marked with different [AcceptVerbs] attributes). So, given the following two methods, I would like the above request to be dispatched to the second one:
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }
Does anybody know if this is possible? And how much work would it be to do so...?
You won't be able to use the [AcceptVerbs] attribute as-is since it's tied to the request's actual HTTP verb. Fortunately the [AcceptVerbs] attribute is very simple; you can see the source for yourself at http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.
In short, subclass AcceptsVerbsAttribute and override the IsValidForRequest() method. The implementation would be something like the following:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
Levi's answer is great. Additionally, I added a check in the custom AcceptsVerbsAttribute that also examines the FORM collection, so you can simply put a hidden input to trigger the DELETE (similar to MVC 2's Html.HttpMethodOverride(HttpVerbs.Delete)).
<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />
Change the incomingVerb assignment to:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;
Be careful with this approach! See a related post by Stephen Walther.
Hopefully this helps someone.
Insert to Form:
<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
This conversation is a bit old, but I wanted to share what I have found using mvc 2:
Browsers support two HTTP verbs: GET and POST, but ASP.NET MVC 2 allows you to simulate Put, Get, and Delete using Html.HttpMethodOverride helper method. Internally, this works by sending the verb in an X-HTTP-Method-Override form field. The behavior of HttpMethodOverride is used by the [AcceptVerbs] attribute as well as the new shorter verb attributes:
For example, the action declaration:
[ActionName("someresource")]
[HttpDelete]
public ActionResult DeleteSomeResource()
should take responsibility for your get request that has the X-HTTP-Method-Override set to Delete.
I'm surprised that this hasn't been mentioned yet, but ASP.NET MVC natively supports X-HTTP-Method-Override and has been doing so from at least version 2. There's no need to write custom code to handle this.
It work in the following way:
Inside AcceptVerbsAttribute (also proxied by [HttpPut], [HttpPost], etc), there's an IsValidForRequest method. Inside that method, it checks with Request.GetHttpMethodOverride(), which returns the proper overriden HTTP method with the following conditions:
Overriding is only supported in POST requests. All others are ignored.
If the X-HTTP-Method-Override value is GET or POST, it's ignored. This makes sense, as you'd never need to override with these values.
It looks for X-HTTP-Method-Override in the following places in this priority:
1) HTTP Header
2) Form Body
3) Query String
If you're really curious, here's how GetHttpMethodOverride() looks (from MVC 3's source code):
public static class HttpRequestExtensions {
internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";
public static string GetHttpMethodOverride(this HttpRequestBase request) {
if (request == null) {
throw new ArgumentNullException("request");
}
string incomingVerb = request.HttpMethod;
if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
return incomingVerb;
}
string verbOverride = null;
string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(headerOverrideValue)) {
verbOverride = headerOverrideValue;
}
else {
string formOverrideValue = request.Form[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(formOverrideValue)) {
verbOverride = formOverrideValue;
}
else {
string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
verbOverride = queryStringOverrideValue;
}
}
}
if (verbOverride != null) {
if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
!String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
incomingVerb = verbOverride;
}
}
return incomingVerb;
}
}
Have you looked at Simply Restful Routing? It already does this.
Edited Feb 2010 to add: Method overrides are built into MVC 2.
The X-HTTP-Method-Override is a custom header and most likely isn't supported by your web container.
Are you calling this from a web page? If so, you should probably use XmlHttpRequest with DELETE (or whatever verb you want). Better yet, use a JS framework to do the heavy lifting for you.
You could create an ActionFilter that implements OnActionExecuting, which fires before the controller action is invoked. You could then interrogate the request headers, and redirect based on the value of the X-HTTP-Method-Override header, when present.