testing in Laravel 5.5 : Class env does not exist - laravel

i am starting tests in laravel
i created a ".env.testing" file with this
APP_NAME=myApp
APP_ENV=testing
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://myApp.localhost
DB_CONNECTION=sqlite_testing
i added this in the "connections" part of config/database.php file
...
'sqlite_testing' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
...
in the phpunit.xml file, i added :
<env name="DB_CONNECTION" value="sqlite_testing" />
and i created a UserTest feature :
class UserTest extends TestCase
{
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
}
public function tearDown()
{
parent::tearDown();
Artisan::call('migrate:reset');
}
public function testCanAccessUserSpace()
{
$user = factory(User::class)->create();
$response = $this->actingAs($user)
->get('/home');
$response->assertStatus(200);
}
}
But when i run the tests, i have this :
ReflectionException: Class env does not exist
What's wrong with my config ?
thanks

I had same error while running the phpunit:
ReflectionException: Class env does not exist
Here was another problem, I've installed package telescope and phpunit tried to load it while testing:
ReflectionException: Class env does not exist
/var/www/html/mat2/vendor/laravel/telescope/src/Telescope.php:263
/var/www/html/mat2/vendor/laravel/telescope/src/Telescope.php:222
and so on.
I've added to phpunit.xml:
<env name="TELESCOPE_ENABLED" value="false"/>
Afterwards, tests are running fine.
So, it may be package testing related error.

If you are using php artisan test --env=testing, add TELESCOPE_ENABLED=false to your .env.testing file and run php artisan config:cache --env=testing.

In my case, set TELESCOPE_ENABLED to false doesn't solve my problem. I have to issue
php artisan config:clear
I use Laravel 7.

Looks like this exception is thrown for a variety of reasons. In your case the issue is with the tearDown function, in specific order of operations within this function. You should call the parent tearDown at the bottom. So this:
public function tearDown()
{
parent::tearDown();
Artisan::call('migrate:reset');
}
Should be refactored as follows:
public function tearDown()
{
Artisan::call('migrate:reset');
parent::tearDown();
}
I suspect the reason is that the app instance gets destroyed inside Illuminate\Foundation\Testing\TestCase. here is the code from Laravel 5.5:
if ($this->app) {
foreach ($this->beforeApplicationDestroyedCallbacks as $callback) {
call_user_func($callback);
}
$this->app->flush();
$this->app = null;
}

This error can be caused by telescope being turned on in a unit testing environment.
I change the default behaviour of telescope to be off and explicitly turn it on in my .env file.
You can change the default to false for telescope by updating your config/telescope.php file.
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => env('TELESCOPE_ENABLED', false), // Change from true to false here.
You will then have to set: TELESCOPE_ENABLED=true in your .env file. This will ensure that you don't have it accidentally turned on in environments you don't want such as production and unit testing.

Might be a bit late for a reply, but the below line in phpunit.xml solved the issue.
<server name="TELESCOPE_ENABLED" value="false"/>

I faced this issue and found issue in config folder > constants file
I was wrote "asset('/')" function in config file, we can't write such functions in config.
Hope this answer will help someone who stuck like this errors.

You need to rename .env.testing to .env, you already set APP_ENV to testing so there is no need to change your .env to .env.testing
EDIT:
Also try to update your dependencies with composer update and try again, it's not a usual bug, so it's something related to your setup of testing environment

I have the same problem in my config/services.php file, my error was calling the route() method in array. I just removed the method and back to works.

For laravel version 8 change app()->environment() to env('ENV_NAME') like
env('SMS_SERVICE_ENDPOINT')
Example:
Previous: app()->environment() === 'production'
New Format should be env('DEV_ENV') === 'production')
Note: Don't forget to add DEV_ENV=production in your .env file

In laravel 8, don't try to use laravel global helper function or Facade after TestCase::tearDown:
class MyTestCase extends TestCase
{
public function tearDown(): void
{
parent::tearDown();
// This will case this exception: Target class [env] does not exist
echo app()->environment();
}
}
Instead, move method BEFORE parent::tearDown, it will work:
public function tearDown(): void
{
echo app()->environment();
parent::tearDown();
}

For posterity, my problem was something else entirely... I was trying to use config or env values in my unit test's "tearDown" method after calling the parent's implementation, which destroyed the application!
So this obviously does not work:
protected function tearDown(): void {
parent::tearDown();
$environment = App::environment();
...
}
but this will...
protected function tearDown(): void {
$environment = App::environment();
...
parent::tearDown();
}

Related

Get Config in Routes tested?

I need to make my routes conditional, based on config:
//routes/auth.php
if (config('auth.allow_registration')) {....
The above config param is set in the config file:
//config/auth.php
'allow_registration' => false,
It is all working fine, until I try to unit-test it
public function test_registration_screen_can_be_rendered()
{
config()->set('auth.allow_registration', true);
$response = $this->get('/register');
$response->assertStatus(200);
}
The test case is failing.
I understand that after I change config, I need to reread routes. But how?
I found only this $this->refreshApplication(); it suppose to reread routes, but it also rereads the config.
How can I only reread routes, but keep my modified config intact?
If you change that config parameter's value to be read from an environment variable, then you can override it for a given test class in the setUp() method. When Laravel reads the config, it will first check if there's an environment variable for the value, then fall back on the default if not.
// config/auth.php
'allow_registration' => env('ALLOW_REGISTRATION', false),
// tests/feature/RegistrationEnabledTest.php
namespace Tests\Feature;
use Tests\TestCase;
class RegistrationEnabledTest extends TestCase
{
protected function setUp(): void
{
putenv("ALLOW_REGISTRATION=true");
parent::setup();
}
public function test_registration_screen_can_be_rendered()
{
$response = $this->get('/register');
$response->assertStatus(200);
}
}
If you'd like to set it for all of your tests, you can add it to your phpunit.xml in the php environment section:
<php>
<env name="APP_ENV" value="testing"/>
<env name="ALLOW_REGISTRATION" value="true"/>
</php>
Unfortunately, setting an env only works for either all tests or a given test class, I also couldn't find a way to get it to work for just a single test within a test class ($this->refreshApplication() doesn't seem to respect the env change), and manually changing routes at runtime is not something Laravel is designed for. However, I think it's a reasonable workaround to separate out tests of various config settings into discrete test classes.
You can use a middleware on routes witch you want to have conditions for access. then you can just use the middleware on the route or in your controller. you can learn about it in Laravel good documentation here.

JWTGenerateCommand::handle() does not exist

I am using Laravel 5.4 and JWT Auth Library for user authentication in API development. After installation while i am running php artisan jwt:generate then it throws me error of
Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist
Any idea what i am missing ?
This error generally display when you install jwt package in laravel 5.5 version. then after you set service providers and run following command.
php artisan jwt:generate
then you seen this error message in terminal.
how to resolve it? simple follow this step
Step - 1 Re-install package
composer require tymon/jwt-auth:dev-develop --prefer-source
or the following is a new release package use laravel 6.X
composer require tymon/jwt-auth:1.0.*
in this developement version this errors fixed.
Step - 2 Set Service Provider
'providers' => [
....
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class to
Tymon\JWTAuth\Providers\LaravelServiceProvider::class
],
Step - 3 Generate key
php artisan jwt:secret
i found this solution from here https://laravelcode.com/post/method-tymonjwtauthcommandsjwtgeneratecommandhandle-does-not-exist
Go to JWTGenerateCommand.php file located in vendor/tymon/src/Commands and paste this method
public function handle() { $this->fire(); }
It's never a great idea to change anything in the vendor folder but the there's two ways to deal with this ...
Generate a random string yourself and just change the value in the JWT config file.
Go to Tymon\JWTAuth\Commands\JWTGenerateCommand and change the fire method to handle.
go to given file path
vendor/tymon/jwt-auth/src/Commands/JWTGenerateCommand.php
change function name
public function fire() to public function handle()
run command:
php artisan jwt:generate
I'm publishing this answer because I have crash in this error more than one time.
The only solution I found that it works with Laravel 5.6 is the following:
Add "tymon/jwt-auth": "1.0.0-rc.1" to composer.json and run composer update
Open config/app.php and add the following:
config/app.php:
'providers' => [
/*
* JWT Service Provider...
*/
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],
'aliases' => [
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
],
Execute:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
Finally, execute: php artisan jwt:secret
After all that, when I hit my endpoint for login I got the following exception:
Class Tymon\JWTAuth\Providers\JWT\NamshiAdapter does not exist
This was fixed by:
Open config/jwt.php and change the following:
config/jwt.php:
'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
Finally, note that in order to work your User model should be defined as follows:
class User extends Authenticatable implements JWTSubject
{
...
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
...
}
I can advise one solution. Go to JWTGenerateCommand.php file located in vendor/tymon/src/Commands and paste this part of code public function handle() { $this->fire(); }
I know this is not an elegant solution, but it works. I hope this might help until official fix arrive.
see here for more info
Change fire() function to handle() in this path
vendor/tymon/jwt-auth/src/commands/JWTGenerateCommand.php
In the file path: /vendor/tymon/jwt-auth/src/Commands/JWTGenerateCommand.php
Add public function
public function handle()
{
$this->fire();
}

How do I disable Laravel view cache?

I have an exception in one of my views. However, instead of telling me the name of the view so I can find it and fix it, laravel says it is in app/storage/views/110a3ecc0aa5ab7e6f7f50ef35a67a8b, which is meaningless.
How do I disable this view caching, so that laravel uses and refers to the actual files?
Out of the box? You can't. But you can extend the BladeCompiler class, overriding the method resposible for checking if the view has been expired:
class MyBladeCompiler extends BladeCompiler {
public function isExpired($path)
{
if ( ! \Config::get('view.cache'))
{
return true;
}
return parent::isExpired($path);
}
}
You'll need to replace the BladeCompiler instance in IoC container, with your own compiler:
$app = App::make('app'); // or just $app = app();
$app->bindShared('blade.compiler', function($app)
{
$cache = $app['path.storage'].'/views';
return new MyBladeCompiler($app['files'], $cache);
});
And then you just need to create that key in your app/config/view.php file
<?php
return [
'cache' => false,
'paths' => [base_path().'/resources/views'],
'pagination' => 'pagination::slider-3',
];
Or, like I do here:
return [
'cache' => in_array(App::environment(), ['production', 'staging']),
];
this worked for me... added this to the .env file
CACHE_EXPIRE=-1
In latest version of laravel (> v9.7.0), you can now add inside config/view.php:
'cache' => App::environment('local') ? false : true
Here is the PR: https://github.com/laravel/framework/pull/41859
Solution
open php.ini
opcache.revalidate_freq=0
opcache.fast_shutdown=0
change to this. restart apache.
check your .env file
Change CACHE_DRIVER=file to CACHE_DRIVER=array
If you have artisan, it's easy to clear the cache
php artisan view:clear
If you don't have or don't want artisan (can't think why you wouldn't want it, it's very useful), you can from the root of your project do
cd storage/framework/views/
rm *.php
Laravel Creates view cache file because it has been told to do that. In .env File you will come across cache_driver which has default property as file change it to array.
You can clear cache in this way, as well:
// Clear cache in laravel
Route::get('/clear-cache', function() {
Artisan::call('cache:clear');
// return what you want
return "Cache is cleared";
});
Here is the full answer
Go to vendor/illuminate/BladeCompiler.php
change these 2 lines
use Illuminate\View\Compilers\Compiler;
class BladeCompiler extends Compiler implements CompilerInterface
with the following:
use App\Support\CustomCompiler;
class BladeCompiler extends CustomCompiler implements CompilerInterface
in your app/support folder (or whatever structure you are using)
create the following class
namespace App\Support;
use Illuminate\View\Compilers\Compiler;
class CustomCompiler extends Compiler {
public function isExpired($path) {
if ( !\config('blade.use_cache'))
return true;
return parent::isExpired($path);
}
}
your blade config file will look like this
return [
'use_cache' => false,
'cache' => storage_path('cache'),
'views' => resources_path('views')
];
auto dump and run....
If you are using MAMP, disable OPCache under Preferences, General, PHP-Cahce. just select off. thank me later.
Although some would call this sketchy, this was the quickest and most minimal way to do this on a small application I was working on
On the controller(s) that my routes pointed to:
public function __construct()
{
exec('php /full/path/to/artisan view:clear');
}
A bit late to the party, however.
I had the same issue: the browser not reflecting changes to the php code.
Simple solution for me was:
set the clock on the server to the same time as the dev computer !
sudo date +%T -s "11:14:00"
In development environment, I just add and modify the next:
bootstrap/start.php
$env = $app->detectEnvironment(function(){return 'testing';});
app/config/testing/cache.php add in array
'cache' => false,
app/config/view.php add in array
'cache' => false,

Class 'Eloquent' not found when mocking in Laravel

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');
}

Laravel 4 model unit test with Codeception - Class 'Eloquent' not found

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!

Resources