Unit testing helpers in CakePHP - unit-testing

I created a new helper called AdvHtmlHelper.
class AdvHtmlHelper extends AppHelper {
var $helpers = array('Form');
function textbox($fieldName, $options = array()) {
$output = $this->Form->input($fieldName, array('before' => '<div class="outerdiv"><div class="leftfields"><div class="txt1">', 'between' => '</div><div class="colon"> : </div></div><div class="rightfields"><div class="input">'));
$output .= '</div></div></div><div class="space"></div>';
return $output;
}
}
And I created a test for it
App::import('Helper', 'AdvHtml');
App::import('Helper', 'Form');
App::import('Helper', 'Html');
App::import('Core', 'View');
class AdvHtmlTest extends CakeTestCase {
private $advHtml = null;
//Here we instantiate our helper, and all other helpers we need.
public function startTest() {
$this->advHtml = new AdvHtmlHelper();
$this->advHtml->Form = new FormHelper();
$this->advHtml->Form->Html = new HtmlHelper();
$this->view = new View($this->Controller);
}
//testing textbox() function.
public function testTextbox() {
$result = '<div class="input text"><div class="outerdiv"><div class="leftfields"><div class="txt1"><label for="new">New</label></div><div class="colon"> : </div></div><div class="rightfields"><div class="input"><input name="data[new]" type="text" id="new" /></div></div></div></div><div class="space"></div>';
$this->assertEqual($result, $this->advHtml->textbox('new'));
}
}
I get the following error when I try to run the test. Line 10 of the helper code is the call to the form helper.
Fatal error: Call to a member function input() on a non-object in /opt/lampp/htdocs/mali/app/views/helpers/adv_html.php
How do I test a helper which calls another helper?
on line 10
EDIT: Answered. Updated with my final test case for reference.

You have to set the form helper as a property of the advHtml helper when setting up the helpers:
public function startTest() {
$this->advHtml = new AdvHtmlHelper();
$this->advHtml->Form = new FormHelper();
}

Related

livewire "render" method must run instance of View

Hey I am trying to use livewire for the first time and I successfuly done the function and when its finish the function checkSingleLink() its shows this error :
"render" method on [App\Http\Livewire\SingleAsset] must return instance of [Illuminate\View\View]
the Livewire Model
namespace App\Http\Livewire;
use Illuminate\Http\Request;
use App\Models\Links;
use App\Models\Cron;
use Livewire\Component;
class SingleAsset extends Component
{
public $saved = False;
protected $fillable = [
'keyword', 'data', 'updated_at'
];
public function __construct() {
$this->cron = new Cron();
}
public function render(Request $request)
{
if(Links::where('asset_id', '=', $request->id)->exists()){
$links = Links::where('asset_id', '=', $request->id)->get();
return view('livewire.single-asset', compact('links'));
}
}
public function checkSingleLink(Links $link, $keyword) {
// cron::fetchUrl($link->link, $keyword);
$data = $this->cron->fetchUrl($link->link, $keyword);
$link->keyword = $keyword;
$link->data = $data;
$link->save();
// dd($this->cron->fetchUrl($link->link, $keyword));
session()->flash('message', "link checked");
$this->saved = TRUE;
}
}
this is the location where I call the function
<input class="inputs" style="border:0;" type="text" value="{{$link->keyword}}" wire:keydown.enter="checkSingleLink({{$link}}, $event.target.value)"/>
this part of the calling and making the function working but after when he need to render again the response its not working

Why listing of items is empty in calling method of the component?

with livewire 2 I have listing of items ($itemDataRows var) and I need for any item show checkbox ($selectedItems var) and
"Select all" button and clicking on this button all items must be selected. I do :
class CrudItems extends Component
{
private $itemDataRows = [];
public $selectedItems = [];
...
public function render()
{
...
$this->itemDataRows = Item
::orderBy('created_at', 'desc')
...
->paginate($backend_per_page);
return view('livewire.admin.items.crud-items', [
'itemDataRows' => $this->itemDataRows,
'item_rows_count' => $this->item_rows_count
])->layout('layouts.admin');
}
}
public function calcSelectedItemsCount()
{
$ret= 0;
foreach( $this->selectedItems as $next_key=>$next_value ) {
if($next_value) {
$ret++;
}
}
return $ret;
}
public function selectAllItems()
{
$this->selectedItems= [];
\Log::info( dump($this->itemDataRows, ' -0 $this->itemDataRows selectAllItems::') );
// INL OG FILE_I SEE THAT ARRAY ABOVE IS EMPTY!!!
foreach( $this->itemDataRows as $nextItemDataRow ) {
$this->selectedItems[$nextItemDataRow->id] = true;
\Log::info( dump($this->selectedItems, ' -$this->selectedItems INSIDE selectAllItems::') );
}
\Log::info( dump($this->selectedItems, ' -$this->selectedItems selectAllItems::') );
}
and in template :
$selectedItems::{{ var_dump($selectedItems) }}<hr>
$itemDataRows::{{ $itemDataRows }}
/* $selectedItems is filled ok when I click on checkboxes , but $itemDataRows shows empty var, though I filled items listing below */
#foreach ($itemDataRows as $item)
<tr>
<td class=" whitespace-nowrap ">
<x-jet-checkbox id="is_reopen" type="checkbox" class="editor_checkbox_field ml-4" title="On saving editor will be opened"
wire:model="selectedItems.{{ $item->id }}"/>
</td>
Is something wrong with definition of $itemDataRows ? Why $itemDataRows is empty in selectAllItems method, but on my template all items are visible ok....
Thanks in advance!
In Livewire you can pass the data via the class variables. And in the mount function you can fill the variable. For Example.
Important Note: The Class Vars must be public!
public $selectedItems = [];
public function mount(): void
{
$this->selectedItems = ['data' => 'Hello World'];
}
public function render()
{
return view('livewire.admin.items.crud-items')->layout('layouts.admin');
}
Update
This must have something to do with the Livewire Lifecyle. Every Livewire component goes through a lifecycle. Lifecycle hooks allow you to run code at any stage of the component's lifecycle or before updating certain properties. In your case, use the mount hook.
You initialise the variable itemDataRows in the render function. A request then calls the method selectAllItems. There you have to initialise itemDataRows again, because the state is no longer there during render or mount.
Solution: create a method getItemDataRows()
private getItemDataRows()
{
$this->itemDataRows => Item::orderBy('created_at', 'desc')
...
->paginate($backend_per_page);
}
then you can call those in the render method and in the selectAllItems method too.
public function selectAllItems()
{
$this->selectedItems= [];
$this->itemDataRows => $this->getItemDataRows();
...
// your code
}

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.

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

Zend Framework: How to unit test a model using Zend_Service_Twitter

I have been getting into Unit Testing with Zend Framework. I am getting used to the other things it provide but I am having a hard time understanding Mock Objects.
For this example, I am trying to use a Mock Object to test out my model.
<?php
class Twitter_Model_Twitter
{
private $_twitter;
/**
* Make the options injectable.
* __contruct($auth, $key)
*/
public function __construct()
{
$config = new Zend_Config_Ini(APPLICATION_INI, APPLICATION_ENV);
$key = $config->encryption->salt;
$iv_size = mcrypt_get_iv_size(MCRYPT_XTEA, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$password = mcrypt_decrypt(MCRYPT_XTEA, $key, $password, MCRYPT_MODE_ECB, $iv);
$this->_twitter = new Zend_Service_Twitter($username, $password);
}
public function verifyCredentials()
{
return $this->_twitter->account->verifyCredentials();
}
public function friendsTimeline($params)
{
return $this->_twitter->status->friendsTimeline($params);
}
}
For my unit test:
require_once ('../application/models/Twitter.php');
class Model_TwitterTest extends ControllerTestCase
{
/**
* #var Model_Twitter
*/
protected $_twitter;
public function testfriendsTimeline()
{
$mockPosts = array('foo', 'bar');
//my understanding below is:
//get a mock of Zend_Service_Twitter with the friendsTimeline method
$twitterMock = $this->getMock('Zend_Service_Twitter', array('friendsTimeline'));
/*
line above will spit out an error:
1) testfriendsTimeline(Model_TwitterTest)
Missing argument 1 for Mock_Zend_Service_Twitter_9fe2aeaa::__construct(), called in
/Applications/MAMP/bin/php5/lib/php/PHPUnit/Framework/TestCase.php on line 672 and
defined /htdocs/twitter/tests/application/models/TwitterTest.php:38
*/
$twitterMock->expects($this->once())
->method('friendsTimeline')
->will($this->returnValue($mockPosts));
$model = new Twitter_Model_Twitter();
$model->setOption('twitter', $twitterMock);
$posts = $model->friendsTimeline(array('count'=>20));
$this->assertEquals($posts, $mockPosts);
}
}
How would you test the following?
1) verifyCredentials()
2) friendsTimeline()
Thanks,
Wenbert
I am going to answer this question. I think I have made this work thanks to zomg from #zftalk.
Here is my new Twitter Model:
<?php
//application/models/Twitter.php
class Twitter_Model_Twitter
{
private $_twitter;
private $_username;
private $_password;
public function __construct(array $options = null)
{
if (is_array($options)) {
$this->setOptions($options);
$this->_twitter = new Zend_Service_Twitter($this->_username, $this->_password);
} else {
$twitterAuth = new Zend_Session_Namespace('Twitter_Auth');
$config = new Zend_Config_Ini(APPLICATION_INI, APPLICATION_ENV);
$key = $config->encryption->salt;
$iv_size = mcrypt_get_iv_size(MCRYPT_XTEA, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$password = mcrypt_decrypt(MCRYPT_XTEA, $key, $twitterAuth->password, MCRYPT_MODE_ECB, $iv);
$username = $twitterAuth->username;
$this->_twitter = new Zend_Service_Twitter($username, $password);
}
}
public function setOptions(array $options)
{
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$pieces = explode('_', $key);
foreach($pieces AS $piece_key => $piece_value) {
$pieces[$piece_key] = ucfirst($piece_value);
}
$name = implode('',$pieces);
$method = 'set' . $name;
//$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
//I added this method. So that I could "inject"/set the $_twitter obj
public function setTwitter($obj)
{
$this->_twitter = $obj;
return $this;
}
public function verifyCredentials()
{
return $this->_twitter->account->verifyCredentials();
}
public function friendsTimeline($params)
{
return $this->_twitter->status->friendsTimeline($params);
}
//in the real code, more will go here...
}
And in my Unit Test, I have this:
<?php
// tests/application/models/TwitterTest.php
require_once ('../application/models/Twitter.php');
class Model_TwitterTest extends ControllerTestCase
{
public function testVerifyCredentials()
{
$stub = $this->getMock('Zend_Service_Twitter', array('verifyCredentials'),array(),'',FALSE);
//FALSE is actually the 5th parameter to flag getMock not to call the main class. See Docs for this.
//Now that I have set the $_twitter variable to use the mock, it will not call the main class - Zend_Rest_Client (i think)
$stub->expects($this->once())
->method('verifyCredentials');
$model = new Twitter_Model_Twitter();
//this is the part where i set the $_twitter variable in my model to use the $stub
$model->setOptions(array('twitter'=>$stub));
$model->verifyCredentials();
}
}
Anyways, I think I got it working.
1) The unit test no longer tried to connect to twitter.com:80
2) After I got the setOptions() working in the Twitter_Model, $model->verifyCredentials() in my unit test was successfully called.
I will wait for others in Stackoverflow to confirm that is the right answer. For the meantime, would like to hear from you guys.
Thanks!!!