Laravel Testing/phpunit, Too few arguments passed when using dependency injection - laravel

I'm trying to create a simple test with Laravel. My test code is as below;
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Http\Controllers\Abc\AbcController;
class AbcTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
private $abcController;
public function __construct (AbcController $abcController) {
$this->abcController = $abcController;
}
public function testExample()
{
$this->assertTrue(true);
}
However, when i run the test, i'm hitting this error,
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function Tests\Feature\abc::__construct(), 0 passed in /var/www/nex/backend/vendor/phpunit/phpunit/src/Framework/TestSuite.php on line 151 and exactly 1 expected in /var/www/nex/backend/tests/Feature/abc.php:28
I've been using this method of performing dependency injections for the rest of my project. I'm not sure why its not working on this particular code.
All help is appreciated.
Thanks!

Check https://laravel.com/docs/5.8/testing you should not use Dependency Injection on controller. Instead you should call the endpoint.
Example
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Http\Controllers\Abc\AbcController;
class AbcTest extends TestCase
{
public function testExample()
{
$response = $this->get('/url');
$response->assertOk();
}
}

Related

Laravel - Test with Artisan seed fails

I am trying to be able to load seed data inside of a Laravel test case but I keep encountering the error below.
<?php
namespace Tests\Feature;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class MagicTest extends TestCase
{
protected function setUp(): void
{
Artisan::call('db:seed');
}
public function test_show()
{
echo 'hi';
}
}
But when I try by running php artisan test
RuntimeException
A facade root has not been set.
at vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:334
How can I make this work? Or should I be taking a completely different approach?

PHPUnit tests failing after adding a ViewServiceProvider for sharing data to views

I am relatively new to testing so please forgive me if this a stupid question.
All my tests are failing after I added a ViewServiceProvider to share data with the views.
The error is:
Illuminate\Database\QueryException : SQLSTATE[HY000]: General error: 1 no such table: policies (SQL: select "name", "slug" from "policies")
My tests are making use the the refresh database trait:
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
...
}
Here is an example of the ViewServiceProvider:
namespace App\Providers;
use App\Models\Policy;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function register(): void{...}
public function boot(): void
{
view()->share('policies', Policy::all(['name', 'slug']));
}
}
Every works when browsing the site on front end. Am i missing something? Why are the tests failing?
I will appreciate suggestions on how to make the tests pass.
Edit
It makes total sense what #Donkarnash said but it's also confusing because according to the docs:
So, what if we need to register a view composer within our service provider? This should be done within the boot method. This method is called after all other service providers have been registered, meaning you have access to all other services that have been registered by the framework
See https://laravel.com/docs/8.x/providers#the-boot-method
I found the solution. Creating a view composer solved the problem.
namespace App\Http\View\Composers;
use App\Models\Policy;
use Illuminate\View\View;
class PolicyComposer
{
public function compose(View $view): void
{
$view->with('policies', Policy::all(['name', 'slug']));
}
}
Then I referenced the composer in the ViewServiceProvider
namespace App\Providers;
use App\Models\Policy;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function register(): void{...}
public function boot(): void
{
view()->composer('*', PolicyComposer::class);
}
}

Why doesn't PHPUnit see Laravel Facades?

I have problem with PHPUnit testing and Laravel
Exception: Class 'DB' not found
My TestCase file:
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
}
My CreatesApplication file:
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
This is my Test:
namespace Tests\Unit;
use App\Services\RepetitionService;
use PHPUnit\Framework\TestCase;
class RepetitionServiceTest extends TestCase
{
public function testGetNextIteration()
{
$repetitionService = new RepetitionService;
$nextIteration = $repetitionService->getNextIteration(1);
$this->assertEquals(2, $nextIteration);
}
}
Method that is being tested:
public function getNextIteration(int $lastIteration) : int
{
// some example code (method is not real but code below copied from original method)
\DB::table('cards')->get();
Config::get('params.repeat_iterations');
config('params.repeat_iterations');
}
Commend:
php vendor/phpunit/phpunit/phpunit --configuration phpunit.xml tests/Unit
Versions:
laravel 7
PHP 7.4
PHPUnit 9
Try to use DB from this path
use Illuminate\Support\Facades\DB;

How can I extend Laravel Dusk Browser?

I wish to override \Laravel\Dusk\Browser methods and extend it with my own, plus a few enhancements. Here is what I did so far but it gives me this error:
TypeError: Argument 1 passed to Tests\Browser\SequentialAppTest::Tests\Browser{closure}() must be an instance of Tests\MyBrowser, instance of Laravel\Dusk\Browser given,
called in
/var/www/gtest/vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php on
line 67
/var/www/gtest/tests/Browser/SequentialAppTest.php:135
/var/www/gtest/vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php:67
/var/www/gtest/tests/Browser/SequentialAppTest.php:157
file: tests/MyBrowser.php
<?php
namespace Tests;
class MyBrowser extends \Laravel\Dusk\Browser
{
}
file: tests/Browser/SequentialAppTest.php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Tests\MyBrowser as Browser;
...
class SequentialAppTest extends DuskTestCase
{
....
}
Override newBrowser() in your test or in DuskTestCase:
use Tests\DuskTestCase;
use Tests\MyBrowser as Browser;
class SequentialAppTest extends DuskTestCase
{
protected function newBrowser($driver)
{
return new Browser($driver);
}
}

Dependency resolving with App::make not working when bind is done by a provider in Laravel

I'm using Laravel 5.2. I tried to resolve a dependency in Laravel out of the IOCContainer as follows.(with App::make method)
App/FooController.php:-
<?php
namespace App\Http\Controllers;
use App\Bind\FooInterface;
use Illuminate\Support\Facades\App;
class FooController extends Controller
{
public function outOfContainer(){
dd(App::make('\App\bind\FooInterface')); // Focus: program dies here!!
}
}
Bindings for the FooInterface done in the AppServiceProvider as follows
App/Providers/AppServiceProvider.php:-
<?php
namespace App\Providers;
use App\Bind\Foo;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('\App\Bind\FooInterface', function() {
return new Foo();
});
}
}
Structure of the Foo class as follows.
App/Bind/Foo.php:-
<?php
namespace App\Bind;
class Foo implements FooInterface {
}
Structure of the FooInterface interface as follows:-
<?php
namespace App\Bind;
interface FooInterface {
}
Then I created a route as follows.
Route::get('/outofcontainer', 'FooController#outOfContainer');
But when I navigate to this route it throws an exception with the error text:
BindingResolutionException in Container.php line 748:
Target [App\bind\FooInterface] is not instantiable.
What is going wrong with this?
How to use App:make() with the AppServiceProvider?
In your service provider, you're binding the string '\App\Bind\FooInterface'. In your controller, you're attempting to make the string '\App\bind\FooInterface'. These strings are not the same, as they have differing cases (Bind vs bind). Since the strings are not the same, Laravel cannot find the binding in the container.
Correct the casing in your make statement and it should work:
dd(App::make('\App\Bind\FooInterface'));

Resources