PHPUnit DbUnit table not found - php

I'm getting a very strange error when running a unit test:
PDOException : SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.result' doesn't exist
/var/www/html/project1/rami/tests/Data/Models/DataImportTest.php:60
The test code in question (simplified to try to isolate the problem):
/**
* #covers \Project1\Rami\Data\Models\DataImport::insertData
*/
public function testInsertData(): void {
$this->object->insertData(1);
$sql = 'SELECT request_id
FROM requests
WHERE request_id = 1;';
$queryTable = $this->getConnection()->createQueryTable('result', $sql);
$expectedTable = $this->createArrayDataSet([
'result' => [
[
'request_id' => '1'
]
]
])->getTable('result');
static::assertTablesEqual($expectedTable, $queryTable);
}
What's even more strangely is that assertions in other tests that use assertTablesEqual run and pass fine, it is only this test that is failing. PHPUnit appears to be introspecting a table on the database called "result" when creating the expected table (which does not exist on the database), but it doesn't do that for any of the other tests.
I have tried dropping the database and recreating it, reloading the dev/test environment (a Vagrant box), and even reprovisioning the Vagrant box with a fresh install of MariaDB, all without success.
Googling the error only shows Laravel related problems, with a small handful of similar problems in other PHP frameworks, but nothing related to testing.
The implementation works fine as far as I can tell, and running the query manually on the test database doesn't cause any error.
Any ideas?

Related

Pest errors in random tests, what to do?

I have about 90 tests written with Pest for my Laravel application. Most of the time all the tests pass but sometimes even if I don't make any change to the codebase i get an error.
The error is the same but it occurs of different tests each time. The only thing the tests that fail have in common is the usage of the seed() function.
The database seeds correctly each time I use php artisan db:seed and php artisan migrate:fresh -- seed
• Tests\Feature\Domain\Product\Resources\DeleteProductTest > it can remove a product
InvalidArgumentException
You requested 1 items, but there are only 0 items available.
at tests/Feature/Domain/Product/Resources/DeleteProductTest.php:17
13▕ /** #var \Domain\User\Models\User $bob */
14▕ $bob = User::factory()->create();
15▕ actingAs($bob);
16▕
➜ 17▕ seed();
18▕
19▕ $product = Product::all()->random();
20▕
I am using the RefreshDatabase trait and I am clearing the cache before running the test batch.
Does anyone know why this happens or how to fix it?
Fixed it myself. There was some logic that relied on randomness and sometimes the database wasn't seeded properly.

PHPunit: Problems with testing

I have run into a major problem while writing tests. I am using Laravel 5.6.0 as framework and PHPUnit 7.0 for testing. As a testing DB I have used sqlite with storage in memory. This is from my database.php:
'sqlite_testing' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
But my problem is that I have several places where I use whereRaw, for example $query->whereRaw('STR_TO_DATE(CONCAT(date, " ",from), "%Y-%m-%d %k") < ?', [$before]);. The problem here is that sqlite does not have the STR_TO_DATE or CONCAT functions that MySQL has. So PHPUnut throws a bunch of errors because of that.
My solution was instead using a MySQL DB as testing DB. But this doesn't seem to work since I get several different errors, mostly I have several tests where foreign key constraint fails.
One exaple for this is that I have the following in my Base TestCase setUp method:
if (Schema::hasTable('gym_schedule') && !empty(GymSchedule::createGymSchedules())) {
$this->artisan('db:seed', ['--class' => 'GymScheduleTableSeeder']);
}
This fails every time except the first because it says that a schedùle with id 1 already exists (id is my primary key). I did try to truncate all tables between each test class using tearDown, but that did not help at all, and also the testing became reeeeally slow, like 3 seconds for each test.
So basically that approach does not work either.
I am at a loss. I have tried googling this and searching through StackOverflow. I am open to any suggestion that is not too complicated (either remove all MySQL functions somehow, solve usage of MySQL or anything else really).
Does anyone have a good idea?
Regarding the first part of the question, unit testing a Laravel app when using whereRaw(), this is how I wrote the methods:
$raw_condition = "CONCAT(`country_code`, `number`) = ?";
if (env('DB_CONNECTION') === 'sqlite') {
$raw_condition = "(`country_code` || `number`) = ?";
}
return Model::whereRaw($raw_condition, [$number])->firstOrFail();

Segmentation fault during Laravel Migration

The problem
As per my previous question here, it was pointed out to me that I shouldn't be trying to fill related models in a Laravel Factory (i.e I should fill them in their own factory).
However, I have an observer that looks for the related data during the creation and tries to fill related models (this is so I can create multiple related entities using just the create:: method and a single multistep form). Now, I need to add a check to see if this data is populated in the observer so I don't have to specify it in the factory.
In doing so, I now get a segmentation fault when trying to seed my database. I've narrowed down the cause to this line - without the isset check, it works fine (other than $data['day'] is not specified, hence the check);
Segmentation fault (core dumped)
if(isset($data['day'])) $event->day->fill($data['day']);
Related Code
EventFactory.php
$factory->define(App\Event::class, function (Faker $faker) {
return [
"name" => "A Test Event",
"description" => $faker->paragraphs(3, true),
"event_start_date" => today(),
"event_opening_date" => today(),
"event_closing_date" => tomorrow(),
"user_id" => 1,
"banner_id" => 1,
"gallery_id" => 1,
"related_event_id" => 1,
"status" => "published",
"purchase_limit" => 1000,
"limit_remaining" => 1000,
"delivery_method" => "collection",
"merchandise_delivery_method" => "collection"
];
});
EventObserver.php
public function created($event){
# get all attributes
$data = $event->getAttributes();
# fill any related models
if(isset($data['day'])) $event->day->fill($data['day']);
# save user
$event->push();
}
public function updating($model){
# get all attributes
$data = $model->getAttributes();
# fill any related models
if(isset($data['day'])) $model->day->fill($data['day']);
# save user
$model->push();
}
Other Info
Command: sudo php artisan migrate:reset --seed
Host: Windows 10
VM Environment: Vagrant running Ubuntu 16.04 via HyperV, mounted share with Samba
PHP Version: 7.1.20
Laravel Version: 5.7
Update
Turns out the issue is actually with this line;
$event->push();
Could there be something recursive happening here?
Update 2
With Namoshek's help, I can now narrow it down to the following error from xdebug;
Maximum function nesting level of '256' reached, aborting!
Increasing xdebug.max_nesting_level to 200000 brings back the segfault.
This seems to me like it's stuck in an infinite loop. However, I can't see how calling save() or push() in created would end up calling back to itself. Confused.
This did indeed turn out to be an infinite recursion issue. Eliminating the line:
$event->push(); // this line appears to call update again, which in turn calls push, which calls update etc...
Solved the problem.

laravel 'class not found' error on production

Slightly odd one here.
I have Persons and Actions. Persons can have many Actions, while each Action belongs to only one Person. I'm using Chumper's Datatables to display a list of people, including a count of their actions.
Since migrating to a production (forge) server, I'm getting
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
Class 'action' not found
when calling the datatable. The error shown
/­vendor/­laravel/­framework/­src/­Illuminate/­Database/­Eloquent/­Model.php:721
public function hasOne($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
suggests it's a problem with my hasMany relationship:
# /models/Person.php
class Person extends Eloquent {
public function actions()
{
return $this->hasMany('Action');
}
# /models/Action.php
class Action extends Eloquent {
public function person()
{
return $this->belongsTo('Person', 'person_id');
}
I assume these are fine, however, as it all works locally. Datatables also works fine elsewhere, calling through other items and their related actions with no trouble.
I've tried composer dump-autoload and artisan dump-autoload on the production server, to no avail. The deployment script on forge is below:
git pull origin master
composer install
php artisan migrate --env=production
I can't tell if it's a config issue, a database issue, a code issue or something else entirely. I've been back through the many similar questions but nothing's jumped out. Any help much appreciated.
for who may have the same problem, triple check the casing of your model! I had it wrong, that's why locally on mac was working but not on the server
So I think I'd borked this one myself.
I'd been lazy and left function datatablePersons() in PersonsController.php using an old 'count' method, relying on long-defunct relationships (that caused n+1, so had to be binned), hence it wobbling over an actions class whenever that relationship was called upon.
Datatable functions in other controllers (with a cleaner 'count' method) work fine, so I've just rewritten datatablePersons() to use the same method.
I've not quite got the query right (in eloquent, at least) yet - see this question here: mysql join ON and AND to laravel eloquent - but the class not found error has certainly gone away.
I'm (massively) guessing that the classmap on the local machine hadn't been flushed since whatever was removed was removed, while the production machine is rebuilt every push, hence the disparity...?
Either way, it's no longer an issue.

PHP activerecord exception : Base table or view not found

I am trying out php active record, it's a great ORM, however I am at a standstill.
I have looked around google, blogs, phpactiverecord documentation as well as statckoverflow for days but have not been able to come across a suitable solution to this problem.
I am able to carry out the basic CRUD (insert,fetch, modify and delete) operations however as soon as i validate an object property using a static $validates_uniqueness_of filter, i get
Fatal error: Uncaught exception 'ActiveRecord\DatabaseException'
With message
exception 'PDOException' with message 'SQLSTATE[42S02]: Base table or
view not found: 1146 Table 'test_ar.models' doesn't exist' in
C:\wamp\www\test_AR\AR\lib\Connection.php on line 325
Here is the code i used in full.
<?php
$path_to_AR = "AR/";
include $path_to_AR . "activerecord.php";
ActiveRecord\Config::initialize(function($cfg) {
$cfg->set_model_directory('model');
$cfg->set_connections(
array(
'development' => 'mysql://root:asdf#localhost/test_ar',
'test' => 'mysql://username:password#localhost/test_database_name',
'production' => 'mysql://username:password#localhost/production_database_name'
)
);
});
/*
class user extends ActiveRecord\Model
{
static $validates_presence_of = array(array('username', 'message' => 'Please supply a username')); //this works just fine
static $validates_uniqueness_of = array(array('username'));//this line causes the PDO exception
}
*/
$user = new user();
user::create((array('username'=>'mike','password'=>'test','created'=>time())));
$user::create(array('username'=>'mike')); //cannot even reach this line because of the exeption
References i have tried/looked at
https://github.com/kla/php-activerecord/issues/274 (though i don't really understand what's going on there)
http://www.phpactiverecord.org/projects/main/wiki/Validations#validates_uniqueness_of
http:// blog.felho.hu/what-is-new-in-php-53-part-2-late-static-binding.html
as well as many others.
Platform and php version
I am using php 5.3.4 and using nightly build (May 8 2013) I have almost failed to get my head around this. Please advise on how to correct this.
This has been solved by the question author:
After discussing it with a few developers on github. It seems this is a bug.
The work around was to create a custom validator in the model
public function validate() {
if ($this->is_new_record() && static::exists(array('conditions' => array('username' => $this->username)))) {
$this->errors->add('username', 'This username is already taken');
}
}
I had this error crop up today in a custom application, not Drupal.
my error was the exact same one.
however the issue was that I created the application on a windows server, then moved it to a linux based server.
apparently during creation the windows based application ran just fine, but threw the error mentioned after move to Linux.
THE ISSUE WAS:
--a database table that was created with a capital litter such as statePages... when it was created it was renamed to statepages without the camel case letter.
once I went into the application and where the app connected and drew information from the database, I removed the mismatch capital letter, and the application found the database table just fine and work like expected.
hope this helps someone else.

Categories