I'm trying to use Codeception to run my Laravel 4 unit tests.
Running a test for a simple class with no dependencies works fine. But when I instantiate a model which depends on Eloquent, I get this fatal error:
PHP Fatal error: Class 'Eloquent' not found in /var/www/project/app/models/Role.php on line 4
Unit test:
<?php
use Codeception\Util\Stub;
class TestModel extends \Codeception\TestCase\Test
{
public function testExample()
{
$role = new Role;
$role->name = 'superuser';
$this->assertEquals('superuser', $role->name);
}
}
Model:
<?php
class Role extends Eloquent
{
public function users()
{
return $this->belongsToMany('User');
}
}
Project structure:
I'm running vendor/bin/codecept run unit from the project root, with this file structure:
/project
codeception.yml
/vendor/bin/codecept
/app
/tests
unit.suite.yml
/unit
ExampleTest.php
/models
Role.php
...etc
What am I doing wrong?
By looking at the Codeception L4 sample app, I was able to see how to bootstrap the autoload to resolve this issue, by adding these lines to project/app/tests/_boostrap.php:
include __DIR__.'/../../vendor/autoload.php';
$app = require_once __DIR__.'/../../bootstrap/start.php';
\Codeception\Util\Autoload::registerSuffix('Page', __DIR__.DIRECTORY_SEPARATOR.'_pages');
Edit: when upgrading from Laravel 4.0 to 4.1, it is also necessary to add an extra line:
$app->boot();
I'm probably late to the party, but if you don't need the codecept stuff. You should be extending laravel's implementation of PHPUnit_Framework_TestCase called just TestCase. Like this:
class TestModel extends TestCase {
}
The answer to this question is a little outdated now. With Laravel 5 I got the same error (Class 'Eloquent' not found...) and solved it by copying the code from Laravels base TestCase.php file. This file is used for testing within the Laravel framework (NOT using codeception).
To fix the 'Eloquent not found' error, add the following lines to project/tests/unit/_bootstrap.php
<?php
$app = require __DIR__.'/../../bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
Honestly I'm not sure why it works, but it does! I'll edit if I figure out why or someone comments.
The Eloquent class cannot be found when you are running your unit tests.
Try adding use Illuminate\Database\Eloquent\Model as Eloquent; to Role.php.
You can go to TestCase class and override method refreshApplication (add method to TestCase) with adding auth or some:
protected function refreshApplication()
{
$this->app = $this->createApplication();
$this->client = $this->createClient();
$this->app->setRequestForConsoleEnvironment();
$this->app->boot();
// authenticate your user here, when app is ready
$user = new User(array('username' => 'John', 'password' => 'test'));
$this->be($user);
}
I solved a similar problem with Laravel 4 and Codeception by adding the following lines to _bootstrap.php
$app = require __DIR__.'/../../bootstrap/start.php';
$app->boot();
Hope this helps a fellow googler!
Related
I'm using VisualPHPUnit as a GUI for my unit tests and I want to add it to my Laravel project.
I read this guide but it's obsolete being from 2015. There's no bootstrap.php file in config directory and there are no test_directories and bootstraps variables (I ran grep -rn . -e test_directories is Laravel directory).
Any idea what I can do to be able to add tests with artisan so they are working in VPU? Because Laravel test needs to extend Illuminate\Foundation\Testing\TestCase and VPU test needs to extend \PHPUnit_Framework_TestCase and I can't get it running. Either I don't see the test in VPU when I use Laravel's extend or I can't use Laravel's functions like visit when I use VPU's extend.
Edit:
Here's my PermissionTest.php:
<?php
namespace Visualphpunit\Test;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class PermissionTest extends \PHPUnit_Framework_TestCase
{
protected $baseUrl = 'http://localhost/laravel/public';
public function testExample()
{
$this->visit('/')->see('Logowanie');
}
public function createApplication()
{
$app = require __DIR__.'/../../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
return $app;
}
}
...for which I get this error: Fatal error: Class 'Visualphpunit\Test\Illuminate\Foundation\Testing\TestCase not found in .../laravel/VisualPHPUnit-master/tests/PermissionTest.php on line 10
Is there a way to prevent using 'use' for everything. In Laravel 4 I never used 'use' and everything just worked. I'm now finding out I have to include everything, even 'DB' use DB. This is extremely frustrating and time consuming looking all this up.
My question is, is there an easier way to include everything?
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Customer;
use DB;
class HomeController extends Controller {
}
?>
Thanks
Not really -- this is the Brave New Namespaced world of PHP 5.3+. Your class file above lives in the App\Http\Controllers namespace, which means when you type something like
$object = new SomeClass;
PHP will assume you mean the class App\Http\Controllers\SomeClass.
You'll either, as you complained about, need to use use, or you'll need to use the full classname (with a leading \ to let PHP know to start from the global namespace) whenever you want to use a class
class HomeController extends Controller {
public function someFunction()
{
$result = \DB::query(...);
$customer = new \App\Models\Customer;
//etc...
}
}
This is question is old but I found you can do this based on information from a tutorial by Tejas Jasani: http://www.theappguruz.com/blog/upgrading-from-laravel-4-2-to-5-in-web
Here are the key steps:
1 - Add the app/Http/Controllers directory to the "autoload" classmap directive of your composer.json file.
"autoload": {
"classmap": [
"database",
"app/Http/Controllers"
],
2 - Remove the namespace from the abstract app/Http/Controllers/Controller.php base class.
3 - In app/Providers/RouteServiceProvider.php file, set the namespace property to null
protected $namespace = null;
4 - Run "composer dump-autoload" from the command line.
Creating my first model with Laravel and its stored at app/models/Login.php. It is:
class Login extends Eloquent {
public $timestamps = false;
}
In a Route in routes.php I am getting a Class 'Login' not found on the line $logins = Login::all();
I have run composer dump-auto in the root of the application (above app) and confirmed that the composer.json file contains "app/models", in the autoload classmap.
Thanks!
EDIT
Adding the Route (never mind that it doesn't actually use num yet):
Route::get('/logins/last/{num}', function($num)
{
$logins = Login::all();
return View::make ('logins.last.index')
->with('logins', $logins)
->with('num', $num);
})->where('num', '[0-9]+'
);
Wrap you code with <?php and ?> tags, which tell PHP to start and stop interpreting the code.
I'm following through Jeffrey Way's Laravel Testing Decoded and I've hit an issue I can't seem to fix.
I'm actually work through this tutorial: http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/ Which is an excerpt from his book.
Basically I have a test like so:
class PostsTest extends TestCase {
public function __construct()
{
$this->mock = Mockery::mock('Eloquent', 'Post');
}
And that like for mocking Eloquent and Post returns:
PHP Fatal error: Class 'Eloquent' not found
When I run phpunit. Incidentally if I use Jeffrey's Laravel Generators and just generate some scaffold e.g.
php artisan generate:scaffold post --fields="title:string, body:string"
And run phpunit I get same error. He's using the same:
$this->mock = Mockery::mock('Eloquent', 'Post');
To mock the classes. Does anyone have any suggestions on what the issue could be?
I've been working through the tutorial again from scratch and am still getting the same error. I've pushed it to a public repo so people can see: https://github.com/RyanHavoc/tdd-laravel
Just pull it down, run composer install/update and phpunit.
I found a solution to the issue.
//Causes the Class 'Eloquent' not found error
public function __construct()
{
$this->mock = Mockery::mock('Eloquent', 'Post');
}
//Setting the mocks in the setUp() method instead works
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('Eloquent', 'Post');
}
The problem:
class PostRepostioryInterface not found for line 4 in PostController.php
or in tinkering with the namespace I've even got class
App\Models\Interfaces\PostRepositoryInterface not found
The questions: How to register a namespace in laravel 4? What do I need to do to get L4 to recognise the classes/interfaces at this namespace?
Larave 3 had a $namespaces static object in ClassLoader where you could add namespaces by
Autoloader::namespaces(array(
'App\Models\Interfaces' => path('app').'models/interfaces',
));
I'm not sure if I have that right for laravel 3 but either way, AutoLoader doesn't exist in Laravel 4 and ClassLoader exists but the method namespaces doesn't exist in ClassLoader in Laravel 4.
I've looked at this but it doesn't seem to work without registering the namespace somehow.
Using namespaces in Laravel 4
Example structure:
app/models/interfaces
PostRepostitoryInterface.php
app/models/repositories
EloquentPostRepository.php
namespaces:
App\Models\Repositories;
App\Models\Interfaces;
the files:
PostRepositoryInterface.php
<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface {
public function all();
public function find($id);
public function store($data);
}
EloquentPostRepository.php
<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
class EloquentPostRepository implements PostRepositoryInterface {
public function all()
{
return Post::all();
}
public function find($id)
{
return Post::find($id);
}
public function store($data)
{
return Post::save($data);
}
}
PostController.php
<?php
use App\Models\Interfaces\PostRepositoryInterface;
class PostsController extends BaseController {
public function __construct( PostRepositoryInterface $posts )
{
$this->posts = $posts;
}
Thanks
You probably forgot to do composer dump-autoload. This updates the list of classes Laravel autoloads.
You can read more on composer documentation.
On the laravel irc channel I found out the namespaces should work in L4 without a need for registering them anywhere. This is because the composer dump-autoload adds them to the composer/autoload file for me. So that was not an issue.
The issue turned out to be a typo apparently(I can't find it in the code above but after going through every line copy/pasting the class names and namespaces something changed), and also somehow in my real code I left out the 'use' statement for EloquentPostRepository.php
use App\Models\Interfaces\PostRepositoryInterface;
Now I've hit another wall trying to use the namespaced interface with ioc and the controller constructor (target interface App\Models\Interfaces\PostRepositoryInterface is not instantiable) but I guess that should be a different question.