Laravel - How to use faker in PHPUnit test? - laravel

It's giving me this error when I run the test:
undefined variable $faker.
This is the WithFaker file.
https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Testing/WithFaker.php
<?php
namespace Tests\Unit;
use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class LoginTest extends TestCase
{
use WithFaker;
/**
* A basic test example.
*
* #return void
*/
/** #test */
public function test_example()
{
$user = User::create([
'username' => $faker->firstName(),
]);
}
}

You have to use $this->faker->firstName() not just $faker->firstName()
Update 1
Now when we use WithFaker Trait $this->faker will give us null, to get around this make sure to call $this->setupFaker() first.
e.g.
class SomeFactory
{
use WithFaker;
public function __construct()
{
$this->setUpFaker();
}
}
credit #Ebi

For anyone coming here from 2021. We no longer require the addition of
$this->setUpFaker();
You only need to include the trait as described in the accepted answer.

once you completed installation of Faker.
include autoload file and create instance
$faker = \Faker\Factory::create();
$faker->firstname()
$faker->lastname()
For more information visit

check you seed function run (Faker $faker).

Related

Lumen - Using factory() function in tests make error - Undefined Function

I'm using Lumen 8.3 ,wanted to use factory() function in my tests, it gives me
Undefined Function ,there is nothing useful in the Docs of Lumen
Am i missing something here?
class ProductTest extends TestCase
{
public function test_if_can_send_products_list(){
$products = factory('App/Products',5)->make();
$this->json('post','/payouts',$products)
->seeJson([
'created' => true,
]);
}
}
->
Error: Call to undefined function factory()
It's better to use direct class like that:
$products = factory(Products::class, 5)->create();
don't forget to add Products model usage (namespace).
Edit
You should create Factory:
<?php
namespace Database\Factories;
use App\Products;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ProductFactory extends Factory
{
protected $model = Products::class;
public function definition(): array
{
return [
'name' => $this->faker->unique()->userName()
];
}
}
And add HasFactory Trait to your model:
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Products extends Model {
use HasFactory;
}
you can also use it like this
Products::factory()->count(5)->make();
I just uncommented these lines in app.php file
$app->withFacades();
$app->withEloquent();
Apparently Laravel 8 removed the 'factory' helper, and it seems Lumen followed that path without updating documentation;
#Faesal Answer is the correct way to do it these days;
remember to add use HasFactory; to your Model.

Laravet test case failing, unable to run seed on test case

My test case:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use Illuminate\Http\Response;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class UserTest extends TestCase
{
use RefreshDatabase, WithFaker, DatabaseMigrations;
protected $endPoint = '/dashboard/users';
public function setUp():void
{
parent::setUp();
$this->artisan('migrate:fresh');
$this->artisan('db:seed');
}
public function test_users_list_is_showing_correctly()
{
$this->signIn();
$this->get($this->endPoint)
->assertStatus(Response::HTTP_OK);
}
}
But, I am receiving error:
SQLSTATE[HY000]: General error: 1 no such table: settings (SQL: select "id", "name", "setting_value" from "settings")
It might be throwing error because, I have this code in boot method of AppServiceProvider
config(['settings' => Setting::get(['id','name','setting_value'])]);
How to fix this? Its probably that migration and seeder are not working, but not sure.
Assuming that you are using laravel 8.x and as it can be seen in code that you have used RefreshDatabase trait. You can do something like this:
// Run the DatabaseSeeder...
$this->seed();
// Run a specific seeder...
$this->seed(OrderStatusSeeder::class);
The above code is taken from the official documentation.
Alternatively, you can set
protected $seed = true;
in your base test case class. This will run the seeder before each test that uses RefreshDatabase trait.
You can also define which seeder should run by specifying this
protected $seeder = OrderStatusSeeder::class;
in your test class.
Hope this helps. More information you find here.

Laravel Auth::attemp() is not working, even with valid credentials

This is the unit test which I want to run. This is always failing. I have tried with wrong data. Still it fails and with correct data still it fails. Please someone help me out from this.
If anyone wants to explore more: http://github.com/PawanRoy1997/forum.git
Php Unit Test:
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
/** ##test */
public function login()
{
$data = ['name'=>'some', 'email'=>'some#some.com','password'=>'password'];
User::create($data);
$this->assertTrue(Auth::attempt($data));
}
}
Output:
➜ forum git:(master) ✗ asn test
FAIL Tests\Unit\UserTest
⨯
FAIL Tests\Feature\UserTest
⨯ login
---
• Tests\Unit\UserTest >
Error
Call to a member function connection() on null
at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1571
1567▕ * #return \Illuminate\Database\Connection
1568▕ */
1569▕ public static function resolveConnection($connection = null)
1570▕ {
➜ 1571▕ return static::$resolver->connection($connection);
1572▕ }
1573▕
1574▕ /**
1575▕ * Get the connection resolver instance.
+7 vendor frames
8 tests/Unit/UserTest.php:19
Illuminate\Database\Eloquent\Model::__callStatic()
• Tests\Feature\UserTest > login
Failed asserting that false is true.
at tests/Feature/UserTest.php:19
15▕ public function login()
16▕ {
17▕ $data = ['name'=>'some', 'email'=>'some#some.com','password'=>'password'];
18▕ User::create($data);
➜ 19▕ $this->assertTrue(Auth::attempt($data));
20▕ }
21▕ }
22▕
Tests: 2 failed
Time: 0.31s
➜ forum git:(master) ✗
Actually, I just figured it out that I need to hash the password while creating the user. I forgot to mention that I have updated Laravel then all of this started. In laravel 8.51, Auth::attempt checks for hashed passwords only. But in laravel 8.50 and before, it allows password to be not hashed.
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;
class UserTest extends TestCase
{
/**
* A basic feature test example.
*
* #return void
*/
public function test_example()
{
$data = [
'name' => 'someone',
'email' => 'some#some.com',
'password' => Hash::make('password'),
'confirm_password' => 'password'
];
User::create($data);
$this->assertDatabaseCount('users', 1);
$this->assertTrue(Auth::attempt(['email' => 'some#some.com', 'password' => 'password']));
}
}

Laravel 8 Tests: PHPUnit error: Unknown formatter "unique"

I have written a test that involves a factory. When I execute the test, I get this error:
The data provider specified for Tests\Unit\ExampleTest::testTakePlace is invalid. InvalidArgumentException: Unknown formatter "unique" /var/www/html/api/vendor/fakerphp/faker/src/Faker/Generator.php:249
Expected result
This error should not be shown, I should be able to use $this->faker->unique().
How I tried to fix this problem
By reading the doc again and again (no difference was found) and by reading questions&answers on the Internet (only one question & only one answer were found: to extend Laravel's TestCase but the official documentation, as I mentionned it, says the contrary). (Laravel's TestCase is provided by use Illuminate\Foundation\Testing\TestCase;)
Question
Why doesn't it work and how to fix this bug?
Sources
Test sources
It extends PHPUnit\Framework\TestCase (not Laravel's TestCase) because the documentation says to extend it. Indeed: https://laravel.com/docs/8.x/testing#creating-and-running-tests . This is not the only part of the doc mentionning to extend it.
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Models\Project;
class ExampleTest extends TestCase
{
/**
* #dataProvider provideTakePlaceData
*/
public function testTakePlace($project)
{
$response = $this->json('GET', '/controllerUserProject_takePlace', [
'project_id' => $project->id
]);
}
public function provideTakePlaceData() {
return [
Project::factory()->make()
];
}
}
Controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ControllerUserProject extends Controller
{
public function takePlace(Request $request, $project_id)
{
return;
}
}
The most important: the factory
<?php
namespace Database\Factories;
use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ProjectFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Project::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'id' => $this->faker->unique()->numberBetween(1, 9000),
];
}
}
Change:
use PHPUnit\Framework\TestCase;
to:
use Tests\TestCase;
Why?
When your ExampleTest extends PHPUnit\Framework\TestCase Laravel app is never initialized in tests, and so you don't have access to Laravel features like factories.
The documentation tells you to extend PHPUnit\Framework\TestCase;, but it refers to Unit tests. Feature tests should extend Tests\TestCase. This is something pretty new. Until Laravel 5.8 both unit and feature tests were extending Tests\TestCase by default. I personally just define all tests as feature tests to avoid such issues.
The problem was due to the use of a dataProvider with the use of the factories. More precisely: PHPUnit data providers should not be used when Laravel factories are.
If you are using faker in Factories please make sure these are working correctly regardless (as per example try running Project::factory()->make(); within Laravel Tinker and see the results)
Second common issue (as mentioned above) is the class that you extend your Test with - see above
Third and frequently omitted one that's causing this error, is a missing parent constructor call in the setUp() - (if you use it)
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Models\Project;
class ExampleTest extends TestCase
{
protected Project $project;
public function setUp(): void
{
parent::setUp();
$this->project = Project::factory()->make();
}
I think you need to use the WithFaker trait to use faker :
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Models\Project;
use Illuminate\Foundation\Testing\WithFaker;
class ExampleTest extends TestCase
{
use WithFaker;
// ...
}

Test Case with laravel Dusk showing error 'users_email_unique'

I'm getting error as on below screenshot
Please help me i am trying and for this i have spend too much time but still issue no luck.
I am using laravel official dusk package for front-web testing. When i am running login test case its showing error "users_email_unique" which is above showing in picture. I am using use DatabaseTransactions but it is not reverting my last transaction. For this i am using test database also. Here is my my code:
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
use App\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class LoginTest extends DuskTestCase
{
use DatabaseTransactions;
/**
* A Dusk test example.
*
* #return void
*/
public function test_I_can_login_successfully()
{
$user = factory(User::class)->create([
'email' => 'login#gmail.com',
'password' => bcrypt('password'),
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/')
->type('email', 'login#gmail.com')
->type('password', 'password')
->press('Login')
->assertSee($user->name);
});
}
}
For Dusk you cannot use use DatabaseTransactions. You need to use DatabaseMigrations instead. When you update trait then you should get rid of the error.
You have sample Dusk test in documentation and it looks like this:
<?php
namespace Tests\Browser;
use App\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* A basic browser test example.
*
* #return void
*/
public function testBasicExample()
{
$user = factory(User::class)->create([
'email' => 'taylor#laravel.com',
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
As you see it's also using DatabaseMigrations trait.

Resources