Yii php unit test action create - unit-testing

I have installed php unit in my local server, but I dont understand (reading the php unit help) how to test my action create. My action is this, and the only thing I want to test is if it saves on database.
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate() {
$_class = $this->getClassName();
$model = new $_class;
if (isset($_POST)) {
$model->attributes = $_POST;
$this->armaMensajeABMGrilla($model->save(), $model);
}
$this->renderPartial('create', array(
'model' => $model,), false, true);
}
protected function armaMensajeABMGrilla($guardoOk, $modelo = null) {
if ($guardoOk == true) {
$this->respuestaJSON = array('success' => true, 'mensaje' => 'ok');
} else {
$erroresMensaje = 'Listado de Errores: <br/><ul>';
$i = 0;
if (isset($modelo->errors)) {
foreach ($modelo->errors as $error) {
$erroresMensaje .= '<li>Error(' . $i . '): ' . $error[0] . '</li>';
$i++;
}
$erroresMensaje.='</ul>';
}
$this->respuestaJSON = array('success' => false, 'mensaje' => $erroresMensaje);
}
$this->renderJSON($this->respuestaJSON);
}
How will be the test method? something like this?
public function actionCreateTest(){
$model = new Model;
$this->asserttrue($model->save());
}

write functional tests for testing controllers functionality instead of unit tests,also
the thing that you are asserting here
$this->assertEquals(true,$controller->actionCreate());
if the outcome of $controller->actionCreate() is the value true, which is not!
you are $this->renderPartial() in that and returning nothing, so that statement will never be true.

Related

cakephp 3 undefined property cookie component unit test

I tried to test my component function through unit testing.
My component function below
public function userRole() {
$loginId = $this->Cookie->read('Admin.login_id');
$name = $this->Cookie->read('Admin.name');
$role = $this->Cookie->read('Admin.role');
if (empty($loginId) || empty($name)){
return false;
}
$adminsORM = TableRegistry::get('Admins');
$admin = $adminsORM->find('all', [
'conditions' => ['login_id' => $loginId, 'name' => $name, 'disable' => 0]
])->first();
return empty($admin)? false : $admin->role;
}
And my component testing function below
public $Acl;
public function setUp()
{
parent::setUp();
$registry = new ComponentRegistry();
$this ->Acl = new AclComponent($registry);
}
public function testUserRole()
{
// Test our adjust method with different parameter settings
$this->Cookie->write('Admin.login_id', 'demo12');
$this->Cookie->write('Admin.role', 1);
$this->Cookie->write('Admin.name', 'demo 12');
$output = $this->Acl->userRole();
$this->assertResponseOk();
}
composer testing code
vendor/bin/phpunit --filter testUserRole /d/xampp/htdocs/admin/admin/tests/TestCase/Controller/Component/AclComponentTest.php
error
Notice Error: Undefined property: App\Test\TestCase\Controller\Component\AclComponentTest::$Cookie in [D:\xampp\htdocs\admin\admin\tests\TestCase\Controller\Component\AclComponentTest.php, line 31]
As the error suggests, there is no $this->Cookie property in your unit test. I can only assume that $this->Cookie in your component refers to the Cookie component (which btw is deprecated as of CakePHP 3.5).
If you need to prepare cookies for a regular unit test, and not a controller/integration test (where you could to use the IntegrationTestCase::cookie(), IntegrationTestCase::cookieEncrypted(), IntegrationTestCase::assertResponseOk() methods), then you have to write the cookies directly to the request object, and make sure that you make it available to the component.
Check out the example in the Cookbook on how to test components, it should look something like this:
namespace App\Test\TestCase\Controller\Component;
use App\Controller\Component\MyComponent;
use Cake\Controller\Controller;
use Cake\Controller\ComponentRegistry;
use Cake\Http\ServerRequest;
use Cake\Http\Response;
use Cake\TestSuite\TestCase;
class MyComponentTest extends TestCase
{
public $component = null;
public $controller = null;
public function setUp()
{
parent::setUp();
$request = new ServerRequest();
$response = new Response();
$this->controller = $this->getMockBuilder('Cake\Controller\Controller')
->setConstructorArgs([$request, $response])
->setMethods(null)
->getMock();
$registry = new ComponentRegistry($this->controller);
$this->component = new MyComponent($registry);
}
// ...
}
You can then either define the cookies in the setUp() method, so that they are available in all tests, or you can define them individually per test. Also note that if you're working with encrypted cookies, you should use CookieCryptTrait::_encrypt() to encrypt the cookie data.
// ...
use Cake\Utility\CookieCryptTrait;
use Cake\Utility\Security;
protected function _getCookieEncryptionKey()
{
// the cookie component uses the salt by default
return Security::getSalt();
}
public function testUserRole()
{
$data = [
'login_id' => 'demo12',
'role' => 1,
'name' => 'demo 12'
];
// the cookie component uses `aes` by default
$cookie = $this->_encrypt($data, 'aes');
$request = new ServerRequest([
'cookies' => [
'Admin' => $cookie
]
]);
$this->controller->request = $request;
$output = $this->Acl->userRole();
$this->assertEquals('expected value', $output);
}
See also
Cookbook > Testing > Testing Components
API > \Cake\Utility\CookieCryptTrait
Based on the testing documentation, in order to set your cookies during your test cases, you need to use the function $this->cookieEncrypted('my_cookie', 'Some secret values'):
$this->cookieEncrypted('Admin.login_id', 'demo12');
$this->cookieEncrypted('Admin.role', 1);
$this->cookieEncrypted('Admin.name', 'demo 12');

blank json array in symfony2

i am writing webservice in symfony2 but i facing some problem regarding the output ,as it is giving blank output.
class DefaultController extends Controller {
/**
*
* #Route("/webservices/activity/{id}", name="user_json_activity")
* #Method("get")
*/
public function activityAction($id) {
$em = $this->getDoctrine()->getEntityManager();
$list = $em->getRepository('FitugowebserviceBundle:activity')->findOneById($id);
$r_array = $this->routes2Array($list);
$r = array('activity' => $r_array);
return new Response(json_encode($r));
}
private function routes2Array($routes) {
$points_array = array();
foreach ($routes as $route) {
$r_array = array('activity' => $route->getActivity(),
'icon' => $route->getIcon());
$points_array[] = $r_array;
}
return $points_array;
}
}
When i try to fetch data for id=1 http://domain.org/fitugo/web/app_dev.php/webservices/activity/1 it is giving output as follows
{"activity":[]}
It look very strange that you want get array with findOneById method. The first thing I suggest to add a check that the entity founded by id exist. Then look that findOneById returns and check your controller logic.

Accessing Model in CakePHP Controller Test

I'm new to CakePHP, and I just started writing my first tests. Usually doing Ruby on Rails, my approach to testing a Controller::create action would be to call the create action, and then comparing the number of models before and after that call, making sure it increased by one.
Would anyone test this any other way?
Is there an easy (builtin) way to access models from a ControllerTest in CakePHP? I couldn't find anything in the source, and accessing it through the Controller seems wrong.
I ended up doing something like this:
class AbstractControllerTestCase extends ControllerTestCase {
/**
* Load models, to be used like $this->DummyModel->[...]
* #param array
*/
public function loadModels() {
$models = func_get_args();
foreach ($models as $modelClass) {
$name = $modelClass . 'Model';
if(!isset($this->{$name})) {
$this->{$name} = ClassRegistry::init(array(
'class' => $modelClass, 'alias' => $modelClass
));
}
}
}
}
Then my tests inherit from AbstractControllerTestCase, call $this->loadModels('User'); in setUp and can do something like this in the test:
$countBefore = $this->UserModel->find('count');
// call the action with POST params
$countAfter = $this->UserModel->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
Note that I'm new to CakePHP but came here with this question. Here's what I ended up doing.
I got my idea from #amiuhle, but I just do it manually in setUp, like how they mention in the model tests at http://book.cakephp.org/2.0/en/development/testing.html.
public function setUp() {
$this->Signup = ClassRegistry::init('Signup');
}
public function testMyTestXYZ() {
$data = array('first_name' => 'name');
$countBefore = $this->Signup->find('count');
$result = $this->testAction('/signups/add',
array(
'data' => array(
'Signup' => $data)
)
);
$countAfter = $this->Signup->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
}
I am not sure why it is necessary to test how many times a model is called or instantiated from the controller action.
So, if I was testing Controller::create... my ControllerTest would contain something like:
testCreate(){
$result = $this->testAction('/controller/create');
if(!strpos($result,'form')){
$this->assertFalse(true);
}
$data = array(
'Article' => array(
'user_id' => 1,
'published' => 1,
'slug' => 'new-article',
'title' => 'New Article',
'body' => 'New Body'
)
);
$result = $this->testAction(
'/controller/create',
array('data' => $data, 'method' => 'post')
);
if(!strpos($result,'Record has been successfully created')){
$this->assertFalse(true);
}
}
The main things you want to test for is whether you are getting the right output for the input. And you can use xDebug profiler to easily find out what classes get instnantiated in a particular action and even how many times. There is no need to test for that manually!

Cakephp Geocoding Behaviour

I have been following this tutorial. Basically I want to take an address from a table I have and place that address on a google map. The tutorial seems pretty straight forward, create the table places, put the behavior in and model and what not.
Just kind of confused how I'd actually use that with my existing tables. I've read through the section in the cookbook about behaviors but am still a little confused about them. Mostly about how I'd integrate the tutorial into other views and controllers that aren't within place model?
first you need to add latitude / longitude coordinates to your address table...
you can do that with a writing parser around this google maps api call:
http://maps.google.com/maps/api/geocode/xml?address=miami&sensor=false
once your addresses contain the coordinates, all you need is to pass the coordinates
to a javascript google maps in your view, just copy the source :
http://code.google.com/apis/maps/documentation/javascript/examples/map-simple.html
here is a cakephp 2.0 shell to create latitude / longitude data
to run: "cake geo"
GeoShell.php :
<?php
class GeoShell extends Shell {
public $uses = array('Business');
public function main() {
$counter = 0;
$unique = 0;
$temps = $this->Business->find('all', array(
'limit' => 100
));
foreach($temps as $t) {
$address = $this->geocodeAddress($t['Business']['address']);
print_r($address);
if(!empty($address)) {
$data['Business']['id'] = $t['Business']['id'];
$data['Business']['lat'] = $address['latitude'];
$data['Business']['lng'] = $address['longitude'];
$this->Business->save($data, false);
$unique++;
}
}
$counter++;
$this->out(' - Processed Records: ' . $counter . ' - ');
$this->out(' - Inserted Records: ' . $unique . ' - ');
}
public function geocodeAddress($address) {
$url = 'http://maps.google.com/maps/api/geocode/json?address=' . urlencode($address) . '&sensor=false';
$response = #file_get_contents($url);
if($response === false) {
return false;
}
$response = json_decode($response);
if($response->status != 'OK') {
return false;
}
foreach ($response->results['0']->address_components as $data) {
if($data->types['0'] == 'country') {
$country = $data->long_name;
$country_code = $data->short_name;
}
}
$result = array(
'latitude' => $response->results['0']->geometry->location->lat,
'longitude' => $response->results['0']->geometry->location->lng,
'country' => $country,
'country_code' => $country_code,
'googleaddress' => $response->results['0']->formatted_address,
);
return $result;
}
}

CakePHP Unit Testing Fixture Name Conventions Argh?

I've been bashing my head against the wall trying to figure out why I can't get my fixture to load properly. When I attempt to run my test, my layout is rendered. If I comment out the fixture, the test runs properly. I've gone over this 100 times and I can't seem to see what's wrong.
Heres my Videosview.test.php
App::import('Model','Videosview');
class VideosviewTest extends Videosview {
var $name = 'Videosview';
//var $useDbConfig = 'test_suite';
}
class VideosviewTestCase extends CakeTestCase {
var $fixtures = array( 'app.videosview' );
function testIncrementTimer() {
$this->autoLayout = $this->autoRender = false;
$this->Videosview =& ClassRegistry::init('Videosview');
//$video_view = $this->find('first');
$result = $this->Videosview->increment_timer($video_view['Videosview']['video_id'],$video_view['Videosview']['user_id'],1);
$this->assertTrue(true);
}
}
This is my videosview_fixture.php
class VideosviewFixture extends CakeTestFixture {
var $name = 'Videosview';
var $import = array('model' => 'Videosview', 'records' => true);
}
Lot of strange code there, it looks like you don't understand how test are used. The problem doesn't come from your fixture import.
$this->assertTrue(true) will always return true. There is no need to declare VideosviewTest.
As I don't know what your increment_timer method is supposed to do I cannot write a test for it, but let's suppose it returns the value passed + 1:
function increment_timer($id = null){
return $id++;
}
Your test case should be
App::import('Model', 'Videosview');
class VideosviewTestCase extends CakeTestCase {
var $fixtures = array('app.videosview');
function startTest() {
$this->Videosview =& ClassRegistry::init('Videosview');
}
function endTest() {
unset($this->Videosview);
ClassRegistry::flush();
}
function testIncrementTimer() {
$input = 1;
// let's test increment_timer function by asserting true that return value is $input + 1, green bar
$this->assertTrue( $this->Videosview->increment_timer($input) == ($input+1), 'Should return 2' );
// let's test increment_timer function by asserting false that return value is $input + 2, green bar
$this->assertFalse( $this->Videosview->increment_timer($input) == ($input+2), 'Should not return 3' );
//the following returns an error as return value is not equal to $input + 2, Red bar
$this->assertTrue( $this->Videosview->increment_timer($input) == ($input+2), 'Should return 2' );
}
}
This is what you should get, and have expected