I am writing an unit test case for my zf2 controller action. But I am stuck in posting the data to controller from unit testcase script.
The test is for login controller action . Login controller is checking for empty username and password. if true it will do the login action steps else redirect to login page.
The problem is I am passing data using the below code to controller. But controller is recieving empty array. I am using php unit version 4.8 and zf2. Is there any alternative way to pass the data(I mean post the data).
$postData = array(
array('login' => 'loginusername','password' => 'test')
);
$this->dispatch('/login', 'POST', $postData);
You should probably pass a \Zend\Http\Request object to the dispatch method:
$parameters = new \Zend\Stdlib\Parameters();
$parameters->fromArray(array('login' => 'loginusername','password' => 'test'));
$request = new \Zend\Http\Request();
$request->setPost($parameters);
$controller->dispatch($request);
Related
Symfony has a pretty clear code example on how to override the request class, but I do not know where in my App I should place it. I receive the request object from Symfony in my controller actions and want to get the SpecialRequest Object instead.
I already tried a kernel.request listener, but this seems to be too late. Is there a place where this kind of initialization code would fit?
Request::setFactory(function (
array $query = array(),
array $request = array(),
array $attributes = array(),
array $cookies = array(),
array $files = array(),
array $server = array(),
$content = null
) {
return SpecialRequest::create(
$query,
$request,
$attributes,
$cookies,
$files,
$server,
$content
);
});
http://symfony.com/doc/current/components/http_foundation/introduction.html#overriding-the-request
In the example given, the Request::setFactory method is called immediately prior to calling the Request::createFromGlobals method. This would imply that the appropriate place for calling this method would be in the front controller, e.g. app.php, app_dev.php and any other file used as a front controller.
In fact the Request::createFromGlobals method and the Request::create method check to see whether a callable has been set by the Request::setFactory method, and if so they use this callable to create an object that should extend the Request class.
I would like use a method of controller from another bundle, in my controller.
The method this->forward need a Response object, and i don't know how to use it.
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
// ... further modify the response or return it directly
return $response;
}
And i saw that i can use service but i want to know if its the best solution or they are another.
$this->forward takes arguments in this order:
Logical Name of controller action in string format i.e. 'AcmeHelloBundle:Hello:fancy'
Parameters to be passed as request variables in array format i.e. array(
'name' => $name,
'color' => 'green',
)
These parameters can be accessed in the controller using request access functions.
Sometimes you want to bypass security completely and run a command in another controller despite a user's permissions level. Luckily you can do that fairly easily.
First, run a use Command for your controller at the top of the controller you want to use the data from:
use AppBundle\Controller\MySourceDataController;
Then call that function from within your destination controller:
$response = MySourceDataController::getTheData( $option1, $option2 );
If you need to pass a Request object, you can do it this way:
$response = MySourceDataController::getTheData( new Request( array(
'server' => 'USAServer1',
) ), $option2 );
This returns a Request with the set parameter of server. I also defined a $option2, this would be a variable often defined in the URL such as:
* #Route("/mydata/{server}/", name="api-source-data")
* #param Request $request
* #param $server
Lastly, if you're passing JSON in that controller and want to convert it back to an object, you can run this bit of code on the $response:
if ( 0 === strpos( $response->headers->get( 'Content-Type' ), 'application/json' ) ) {
$response = json_decode( $response->getContent(), true );
}
Voila. Access any controller form any other controller and bypass security notation for the source controller. :)
I'm having some trouble using Laravel's Input::replace() method to simulate a POST request during unit testing.
According to Jeffrey Way here and here, you can do something like this:
# app/tests/controllers/PostsControllerTest.php
public function testStore()
{
Input::replace($input = ['title' => 'My Title']);</p>
$this->mock
->shouldReceive('create')
->once()
->with($input);
$this->app->instance('Post', $this->mock);
$this->call('POST', 'posts');
$this->assertRedirectedToRoute('posts.index');
}
However, I can't get this to work. Input::all() and all Input::get() calls still return an empty array or null after Input::replace() is used.
This is my test function:
public function test_invalid_login()
{
// Make login attempt with invalid credentials
Input::replace($input = [
'email' => 'bad#email.com',
'password' => 'badpassword',
'remember' => true
]);
$this->mock->shouldReceive('logAttempt')
->once()
->with($input)
->andReturn(false);
$this->action('POST', 'SessionsController#postLogin');
// Should redirect back to login form with old input
$this->assertHasOldInput();
$this->assertRedirectedToAction('SessionsController#getLogin');
}
The $this->mock->shouldReceive() doesn't get called with $input though - it only gets an empty array. I've confirmed this in the debugger by looking at Input::all() and Input::get() for each value, and they're all empty.
TL/DR: How do I send a request with POST data in a Laravel unit test?
You should use Request::replace(), not Input::replace in order to replace input data for the current request.
First, let's get into the application's context:
We are on CustomerController, which is a Resource Controller sending a post request to the Store method.
This is my store method:
$customerDTO = new \repositories\dtos\CreateCustomerDTO();
$customerDTO->hydrate( Input::All() );
/** #var Customer $customer */
$customer = $this->customers->create( $customerDTO );
if ( $customer != null ){
header('Location: '.url('/customers/'.$customer->clacli));
return Redirect::action('CustomerController#show', array($customer->id) );
}
$userMessage = array(
'messageType' => 'error',
'messageContent' => 'Error creating a new Customer'
);
return Redirect::action('CustomerController#index')
->with(array('userMessage' => $userMessage));
I had to put a "header" because the Redirect call is not working.
When i put this line:
$customer = $this->customers->create( $customerDTO );
All the redirects stops to work.
And what is inside $this->customers? It's just a repository to abstract the database from the controller, i'm going to need to change the database on the near future.
Well, the code inside $this->customers->create is:
return Customer::create( $dto->toArray() );
And it's working, also all the test of my customersRepository are working. It's just a call to the Eloquent Model create method with an array of data.
So i can't figure out why the Redirect is not working. Any tip?
I tried with return 'test'; just after the call to $this->customers->create( $customerDTO); and didn't work either.
It was a strange problem with the sessions. We get it fixed, not sure why...
I am dispatching some POST data to an action of a controller. That action echoes some json-encoded string. I want to verify that the json-encoded string of that action is as I want it. I want to know how I can get that string?
My test looks like this:
$this->request->setMethod('POST')
->setPost(['test' => 'databaseschema_Database']);
$params = ['action' => 'analysis', 'controller' => 'Index', 'module' => 'default'];
$urlParams = $this->urlizeOptions($params);
$url = $this->url($urlParams);
$result = $this->dispatch($url);
$this->assertJsonStringEqualsJsonString(
$result, json_encode(["status" => "Success"])
);
My test is failing and I am getting following message:
1) IndexControllerTest::testAnalysisAction
Expected value JSON decode error - Unknown error
stdClass Object (...) does not match expected type "NULL".
Can any one guide me on how to do this?
If you want to do unit testing, what you really want to do is extract the json encoding into it's own class (or a method inside a utils class or something) and then test those method instead of your whole controller.
The problem with your approach is that when running phpunit, there is not $_POST array. The code above does not show what is happening, but I guess there is different behaviour when run through apache and cli which causes your test to fail.
I would create a TransformerClass and test this in isolation:
class JsonTransformer
{
public function transformPostData(array $postArray)
{
// transformation happening
}
}
class JsonTransformerTest extends \PHPUnit_Framework_TestCase
{
public function testTransformPostData()
{
$transformer = new JsonTransformer();
$data = array('action' => 'analysis', 'controller' => 'Index', 'module' => 'default');
$result = $transformer->transformPostData(data);
$this->assertJsonStringEqualsJsonString($result, json_encode(array("status" => "Success")));
}
}
If you need to test your whole request/response, you would use some kind of HTTPClient, request the url, send the post data and see if the response is what you'd expect.
Everything in between (like faking the post data) leaves you with more problems and more code to maintain than it does you good.