PhpUnit: The http response is empty though test is carried out fine - php

I am trying to write unit tests for practice on a small application. This is my first time with unit-tests and I have not a very good knowledge. This is what I am trying to do.
$response=$this->request('POST',['crud_controller','add_data' ,$data]);
$this->assertEquals(1,$response);
The function add_data is programmed to return 1 if the data is processed or return -1 otherwise. The data is getting processed but phpUnit shows failed test with
issue:
Failed asserting that null matches expected 1.
I am working in codeigniter and using phpunit for testing.
Complete Test-Case:
<?php
class crud_controller_test extends TestCase{
public function test_add_data(){
$data =array(
'name' => 'badPass',
);
$response=$this->request('POST',['crud_controller','add_data' ,$data]);
$this->assertEquals(1,$response);
//$this->assertEquals(-1,$response);
//$this->assertEquals(0,$response);
}
public function test_update_data(){
$data =array(
'id'=>'29',
'name' => 'badPass',
);
$response=$this->request('POST',['crud_controller','update_data' ,$data]);
var_dump($response);
$this->assertEquals(1,$response);
//$this->assertEquals(-1,$response);
//$this->assertEquals(0,$response);
}
}
?>
Methods getting called:
public function add_data($data){
if($this->crud_model->insert($data) ==true)
return 1;
else
return -1;
//return $this->crud_model->insert($data);
//$this->index();
}
public function update_data($data){
if($this->crud_model->update($data) == true)
return 1;
else
return -1;
//$this->index();
}

Related

PHP testing emptying out collection

I'm currently trying to write PHP tests using pest for a search feature within a chat component. The component works fine when being used in my test environment though i'm unable to get a certain test to pass. The objective is to be able to return multiple messages that meet a specific search term.
Here is the test itself in ChatSearchTest.php:
/** #test */
public function the_component_can_return_multiple_search_results()
{
$messages_fixed_content = ChatMessage::factory(2)
->for($this->members[0], 'from')
->for($this->members[1], 'to')
->create([
'content' => 'test123'
]);
$messages_random_content = ChatMessage::factory(1)
->for($this->members[0], 'from')
->for($this->members[1], 'to')
->create();
$messages = $messages_fixed_content->merge($messages_random_content);
$chat_search = 'test123';
$component = Livewire::test(ChatSearch::class, ['partnership' => $this->partnership])
->set('chat_search', $chat_search)
->call('getSearchResults', $chat_search);
->assertCount('messages', 2);
}
And the relevant code it's testing in ChatSearch.php:
public function updatedChatSearch()
{
$this->getSearchResults();
}
public function getSearchResults()
{
$search_results = $this->getMessagesQuery()->get();
$this->messages = $search_results;
$this->have_results = true;
}
protected function getMessagesQuery()
{
$query = $this->partnership
->chatMessages()
->with('from')
->with('shareable');
if ($this->chat_search) {
$query->search('content', $this->chat_search);
}
$query->latest();
return $query;
}
public function goToMessage($message_id)
{
$this->emitUp('goToSearchResult', $message_id);
}
The issue is that $this->messages returns an empty collection during the test, whereas on the actual testing environment, it works. If I dump out at the end of getSearchResults() it correctly shows $this->have_results as true though $this->messages returns an empty collection, as does $search_results.

Laravel :: Type error: Too few arguments to function App\Product::getTax(), 0 passed

I have this code:
public function taxesData(Product $product)
{
$taxes = \Auth::user()->taxes;
foreach ($taxes as $tax) {
echo "$product->getTax($tax)";
}
}
which on testing gives this error:
Type error: Too few arguments to function App\Product::getTax(), 0 passed in E:\projects\ims\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php on line 411 and exactly 1 expected
However, just a small change makes it works, but I am not able to understand. Why?
public function taxesData(Product $product)
{
$taxes = \Auth::user()->taxes;
foreach ($taxes as $tax) {
echo $product->getTax($tax);
}
}
Please help.
I tried to simplify it for the purpose of posting here... actually i am creating json with html component for a datatable ->
public function taxesData(Product $product)
{
$taxes = \Auth::user()->taxes;
return datatables()
->of($taxes)
->addColumn('check',function($tax) use($product){
if($product->hasTax($tax)){
return "<input type='checkbox' class='input-sm row-checkbox' name='tax[$tax->id]' value='$tax->id' checked>";
}else{
return "<input type='checkbox' class='input-sm row-checkbox' name='tax[$tax->id]' value='$tax->id'>";
}
})
->editColumn('tax', function($tax) use($product){
return "<span class='currencyinput form-control'>
<input id='rate' type='text' name='rate' value='$product->getTax($tax)' required autofocus>
</span>"
})
->toJson();
}
Adding getTax method
public function getTax(Tax $t)
{
if($this->hasTax($t)){
return $this->taxes->find($t->id)->pivot->tax;
}
else{
return $t->pivot->tax;
}
}
public function hasTax(Tax $tax)
{
foreach ($this->taxes as $t) {
if($t->id == $tax->id){
return true;
}
}
return false;
}
It fails because you are not following the correct syntax of echo strings.
This would work:
echo "{$product->getTax($tax)}";
or actually, because you dont' need the quotes for such a simple expression:
echo $product->getTax($tax);
Here's what I've done so far.
Just for simplicity, I've created a sample Model.
// SampleModel.php
public function relatedModels()
{
return $this->hasMany(RelatedModel::class);
}
// this is like an accessor, but since our model doesn't have
// a property called `relatedModels`, Laravel will ignore it
// until later...
public function getRelatedModels()
{
return "Sample";
}
Given the following code, here are the outputs.
$a = SampleModel::find($id);
$a->relatedModels;
// this returns a collection of related models to this model.
$a->getRelatedModels();
// this returns "Sample";
// HOWEVER, when we try to interpolate that member function call.
"$a->getRelatedModels()"
// this throws error that the method `getRelatedModels` must return a relationship.
// I've also tried to add an argument to my existing function to be in-line with your situation.
public function getRelatedModels($a) ...
// this works well
$a->getRelatedModels(1);
// but this, yes, it throws the error as same as what you've got.
"$a->getRelatedModels(1)";
The error pointed out this line in the framework's codebase.
// HasAttributes.php
protected function getRelationshipFromMethod($method)
{
$relation = $this->$method(); // <-- this line
For some reason, doing "$a->getRelatedModels(1)" triggers the __get magic method of the model.
Which branches down to this stack call.
// Model.php
public function __get($key)
{
return $this->getAttribute($key);
}
// |
// V
// HasAttributes.php
public function getAttribute($key)
{
...
return $this->getRelationValue($key);
}
// |
// V
// HasAttributes.php
public function getRelationValue($key)
{
...
if (method_exists($this, $key)) {
return $this->getRelationshipFromMethod($key);
}
}
// |
// V
// HasAttributes.php
protected function getRelationshipFromMethod($method)
{
$relation = $this->$method(); // <-- lastly to this
// $method = "getRelatedModels"
// since our method `getRelatedModels` needs an argument
// this call will fail since it wasn't able to provide an argument.
...
}
That's why you're getting the too few arguments passed exception. I want to investigate further but I have to go home!
I don't know if this is a legit bug for Laravel, but if you do think so, issue it on Laravel's github repository.
UPDATE
I've posted an issue in github and this is one of the comments which truly made sense for me.
This is neither a issue with Laravel, nor with PHP. You are just using the wrong syntax, see it here: https://github.com/laravel/framework/issues/23639
Github user #staudenmeir commented:
"$sampleModel->getRelatedModels()" is equivalent to "$sampleModel->getRelatedModels"."()".
The usage of variables in strings is limited to "$foo" and "$foo->bar". Function calls like "$foo->bar()"
don't work. You can (but shouldn't) use curly braces for that: "{$foo->bar()}"
The better solution is just simple string concatenation:
"text..." . $sampleModel->getRelatedModels() . "more text..."
So that is why the magic method __get is being called.

Inserting data works, but cannot retrieve it from MongoDB using YiiMongoDB Suite

First off I know the developer stopped working on this extension full time, but from what I understand there are still alot of people using it. Hoping someone can help me with this (hopefully simple problem!)
I'm trying to read the data I just inserted into MongoDB using the YiiMongoDbSuite extension.
The data is successfully inserted as I can see it via the mongo console.
The problem is when I try to retrieve it. Here's the code I'm running together - it inserts it (no problem), but can't retrieve it:
<?php
$new = new Character();
$new->playerName = "Yii-Insert-Test";
$new->playerId = "123456789";
$new->playerScore = "9001";
$new->save();
$findAll = Character::model()->findAll();
foreach($findAll as $result) {
echo $result->playerName; // result should be "Yii-Insert-Test", instead it's NULL
}
?>
It does get inserted though:
{
"_id" : ObjectId("54a0deda60fc21843100002a"),
"playerName" : "Yii-Insert-Test",
"playerId" : "123456789",
"playerScore" : "9001"
}
And here's my very simple model Character.php :
<?php
class Character extends EMongoDocument
{
public $_id;
public $playerName;
public $playerId;
public $playerScore;
public function getCollectionName()
{
return 'usercollection';
}
public function rules()
{
return array(
array('playerName', 'required'),
);
}
public function attributeNames()
{
return array(
'playerName' => 'Character Name',
'playerId' => 'Character ID',
'playerScore' => 'Character Score',
);
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
I feel like it's right in front of me but can't see what the problem is.
edit:
slowly figuring it out - looks like I am receiving data, but it's all empty - this is the mongoDB cursor. I'm already doing a forloop to iterate it, so I'll have to figure out what else I'm not doing.

CakePHP testing user model with parentNode() method

I'm trying to learn how to do unit testing in general but specifically the project I'm working on is built with CakePHP. I have this parentNode() method in my user model taken directly from the Simple Acl Controlled Application tutorial.
public function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
if (isset($this->data['User']['group_id'])) {
$groupId = $this->data['User']['group_id'];
} else {
$groupId = $this->field('group_id');
}
if (!$groupId) {
return null; // not tested
} else {
return array('Group' => array('id' => $groupId));
}
}
I wrote the following tests
public function testParentNodeHasNoUserDataOrId() {
unset($this->User->id);
unset($this->User->data);
$this->assertNull($this->User->parentNode());
}
public function testParentNodeWithGroupIDInUserData() {
$this->User->data['User']['group_id'] = 1;
$this->assertEquals(array('Group'=>array('id'=>1)),$this->User->parentNode());
}
public function testParentNodeWithoutGroupIDInUserData() {
$this->User->id = 1;
unset($this->User->data['User']['group_id']);
$this->assertEquals(array('Group'=>array('id'=>1)), $this->User->parentNode());
}
and they all seem to work. My code coverage report however shows that I'm not testing the return null; in the if(!$groupId) block. I can't figure out how to test that line.
As far as I can tell it will never execute. If my User model has no id and no data it returns null in the first if block. if I cheat a bit and give the user some fake data $this->field('group_id') is still returning group 1 (I think it should return false instead but it doesn't)
So when unit testing do you have to test everything? How could I test for the return null if(!$groupId)? If there's code that will never execute should I just remove it?
Thanks!
I figured out how I could test for the "impossible" scenario with the following test
public function testParentNodeWhenUserHasNoGroupId() {
$this->User->id = 1;
$user = $this->User->read();
$user['User']['group_id'] = 0;
$this->User->save($user);
$this->assertNull($this->User->parentNode());
}

PhpUnit check output text

I am starting to write phpUnit test and faced with such problem. 80% of my functions ending on such lines
$data["res"] = $this->get_some_html($this->some_id);
echo my_json_encode($data);
return true;
How can i make test on such kind of functions in my classes?
You need to isolate your code into testable 'chunks'. You can test that the function returns TRUE/FALSE given specified text, and then test the JSON return data given fixed information.
function my_json_encode($data)
{
return ...;
}
function get_some_html($element)
{
return ...;
}
function element_exists($element)
{
return ..;
}
function display_data($element)
{
if(element_exists($element)
{
$data = get_some_html($element);
$json = my_json_encode($data);
return true;
}
else
{
return false;
}
}
Testing:
public function test_my_json_encode()
{
$this->assertEquals($expected_encoded_data, my_json_encode($text));
}
public function test_get_some_html()
{
$this->assertEquals($expected_html, get_some_html('ExistingElementId'));
}
public function test_element_exists()
{
$this->assertTrue(element_exists('ExistingElementId');
$this->assertFalse(element_exists('NonExistingElementId');
}
function test_display_data()
{
$this->assertTrue(display_data('ExistingElementId'));
$this->assertFalse(element_exists('NonExistingElementId');
}
This is a simple, abstract example of the changes and the testing. As the comments above have indicated, you might want to change the return to be the JSON text, and a FALSE on error, then use === testing in your code to decide to display the text or not.
The next step would be to mock out the Elements, so you can get expected data without the need for a real HTML page.

Categories