When executing tests separately I have added this functions to make sure sqlite db would be created if it's not there:
abstract class TestCase extends BaseTestCase
{
use CreatesApplication, DatabaseMigrations;
public function setUp(): void
{
$this->initializeTestDB();
parent::setUp();
Notification::fake();
if ($this->tenancy) {
$this->initializeTenancy();
}
}
public function initializeTestDB(): void
{
$dbname = env('DB_DATABASE');
$filePath= "./" . $dbname;
if (!file_exists($filePath)) {
touch($filePath);
}
}
But this does not help when using php artisan test --parallel. I have tried to move this method into AppServiceProvider as in the documentation. Also didn't helped:
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
ParallelTesting::setUpProcess(function ($token) {
$this->handleTestDB();
});
Any ideas to handle this properly for both parallel and separate tests ?
Related
I'm using Laravel 8 and I'm creating a custom Facade, but I cannot recall it with LogActivity::log($payload) but only with LogActivityFacade::log($payload).
Cannot see where is my fault...
app\Helpers\LogActivityFacade.php
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Facade;
class LogActivityFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'logactivity';
}
}
app\Helpers\LogActivityHelper.php
<?php
namespace App\Helpers;
use App\Repositories\LogActivityRepository;
class LogActivityHelper
{
public function log($payload)
{
$repository = new LogActivityRepository();
$repository->store($payload);
}
}
app\Providers\LogActivityServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\App;
use App\Helpers\LogActivityHelper;
use Illuminate\Support\ServiceProvider;
class LogActivityServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind('logactivity', function() {
return new LogActivityHelper();
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
config/app.php
In providers array
[...]
App\Providers\LogActivityServiceProvider::class,
In alias array
'LogActivity' => App\Helpers\LogActivityFacade::class,
I tried also composer dump-autoload and php artisan config:clear, but I can access to the Facade (and it works...) only with LogActivityFacade::log() instead of LogActivity.
This is the expected behavior. Laravel doesn't create new classes for you it just proxies methods from the service class in the facade using the __call magic method. If you take a peek at, for example, the Auth or Route facade in the vendor directory you will see that they are named Auth and Route respectively not AuthFacade and RouteFacade. So just name your facade LogActivity. If you need to differentiate it from the service class you can use namespacing or just postfix the service class name with something as you have already done.
You can do this for easy access to the facades
namespace App\Facade;
use Illuminate\Support\Facades\Facade;
abstract class BaseFacade extends Facade
{
/**
* #return string
*/
public static function getFacadeAccessor()
{
return static::class ;
}
/**
* #param $class
*/
static function shouldProxyTo($class)
{
app()->singleton(self::getFacadeAccessor(),$class);
}
}
extend other facades
namespace App\Facade\Plugins;
use App\Facade\BaseFacade;
/**
* #method static convertPersianNumberToEnglish($number)
* #method static bool checkDataIsTrue(array $results = [])
* #method static string|null removeFileTypeName(string $string = null)
*/
class GlobalPluginsFacade extends BaseFacade
{
}
register in services provider
public function boot()
{
// global facades
GlobalPluginsFacade::shouldProxyTo(GlobalPluginsRepo::class);
}
And easy to use.
GlobalPluginsFacade::getFunction();
I have service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class InvitationServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind('App\Service\InvitationServiceInterface', 'App\Service\InvitationService');
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
Also there is an custom interface InvitationServiceInterface and InvitationService:
<?php
namespace App\Service;
class InvitationService implements InvitationServiceInterface
{
public function doAwesomeThing()
{
echo 'Do...';
}
}
Interface is:
<?php
namespace App\Service;
interface InvitationServiceInterface
{
public function doAwesomeThing();
}
These both files are place in path:
App\Service\InvitationServiceInterface
App\Service\InvitationService
So, I get an error:
Illuminate \ Contracts \ Container \ BindingResolutionException Target
[App\Service\InvitationServiceInterface] is not instantiable.
Using is:
use App\Service\InvitationServiceInterface;
use App\User;
use Illuminate\Http\Request;
class PassportController extends Controller
{
public function register(Request $request, InvitationServiceInterface $invitationService)
{
}
You can use the laravel service container in the constructor of a controller, i.e.:
class PassportController extends Controller
{
public function _construct(InvitationServiceInterface $invitationService)
{
$this->invitationService = $invitationService;
}
}
But not in a route controller function like you tried because here is the area of the route model binding so the service container is trying to instanciate a route model.
Probably service provider was cached.
Try to delete those two files:
Or run
php artisan config:clear
Or delete them derectry
rm bootstrap/cache/packages.php
rm bootstrap/cache/services.php
I'd like to share data with all views via the AppServiceProvider. Moreover, I'd like to check the guard type first to give some specific output for each user type.
I tried to check the guard in AppServiceProvider via Auth::guard('admin')->check() but it returns false. However, the same if statement works perfectly in my Controllers.
I've also included Illuminate\Support\Facades\Auth and Illuminate\Support\Facades\View.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
if (Auth::guard('admin')->check()) {
// Share data with views
}
}
}
The if statement returns false, although I'm logged in as admin.
you need view composer for this.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Auth;
use DB;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer('*', function ($view)
{
if (Auth::guard('admin')->check()) {
}
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
If you want to pass data in views.
view()->composer('*', function ($view)
{
if (Auth::guard('admin')->check()) {
$admin = DB::table('admins')->first(); // for example
$view->with(compact('admin'));
}
});
Is there a way to call artisan commands before my entire test suite? Installing Cartalyst extensions takes time so I do not want to do it before every test but I am presuming i cannot call facades from a static method like setUpBeforeClass, I receive this error
RuntimeException: A facade root has not been set. in /Users/lance/Desktop/FastLMS/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:218
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
class TestCase extends \Illuminate\Foundation\Testing\TestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
Artisan::call('migrate');
Artisan::call('extension:install');
Artisan::call('extension:enable');
}
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
Hash::setRounds(4);
return $app;
}
public function setUp()
{
parent::setUp();
$this->app['Illuminate\Contracts\Http\Kernel']->disableMiddleware();
}
}
How can i test my function which has __construct ?
For ex my controller code looks like :
namespace App\Http\Controllers;
use App\Repositories\UserAccountRepository;
class UserController extends ProtectedController
{
protected $userAccountRepository;
public function __construct(userAccountRepository
$userAccountRepository){
parent::__construct();
$this->userAccountRepository = $userAccountRepository;
}
public function FunctionWantToTest(){
return 'string';
}
The unit test required to fulfill the construct first before test my FunctionWantToTest.
So, my test code looks like,
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Http\Controllers\UserController;
class UserTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testUserList()
{
$UserController = new UserController(???what value??);
$this->assertTrue(true);
}
}
Need more help (best practice) how to test the code which has construct.
I think you just need to use app->make:
class UserTest extends TestCase
{
protected $userController;
public function setUp() {
parent::setUp();
$this->userController = $this->app->make(UserController::class);
}
/**
* A basic test example.
*
* #return void
*/
public function testUserList()
{
$this->userController // do what you need here...
$this->assertTrue(true);
}
}
Use feature test or integration test when test controller,
You can see this brief explanation about unit test and integration test.
What's the difference between unit tests and integration tests?