Laravel 5.2 testing How to follow DRY principle? - laravel

Everytime I need to test method as authenticated user, I always insert role table because it has relationship with user table, then create new user.
Like this below code.
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Models\User;
use App\Models\Role;
class CouponsTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
use DatabaseMigrations;
//use WithoutMiddleware;
public function test_index_coupon(){
//factory(App\Models\Coupon::class, 5)->create()->toArray();
DB::table('roles')->insert([
['id' => 1, 'name' => 'customer'],
['id' => 2, 'name' => 'partner'],
['id' => 3, 'name' => 'admin'],
]);
$user = User::create([
'id' => 3,
'password' => bcrypt('123456789'),
'email' => 'admin#domain.co.id',
'role_id' => '3',
'status' => 'confirmed',
'balance' => 0,
]);
$this->actingAs($user)->visit('admin/coupons')->seePageIs('admin/coupons');
}
public function test_create_coupon()
{
DB::table('roles')->insert([
['id' => 1, 'name' => 'customer'],
['id' => 2, 'name' => 'partner'],
['id' => 3, 'name' => 'admin'],
]);
$user = User::create([
'id' => 3,
'full_name' => 'Admin Full Name',
'password' => bcrypt('123456789'),
'email' => 'admin#domain.co.id',
'role_id' => '3',
'status' => 'confirmed',
'balance' => 0,
]);
$this->actingAs($user)->visit('admin/coupons/create')->seePageIs('admin/coupons/create');
}
}
I know this is bad practice.
How should my code looks like to follow DRY principle?

It is common to use ModelFactory.php and define factories for your models.
You can also pass arguments to those models.
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
'role_id' => factory(App\Role::class)->create()->id,
];
});
$factory->define(App\Role::class, function(Faker\Generator $faker){
return [
'name' => $faker->name,
];
}
You can then do the following in your test:
$role = factory(App\Role::class)->create(['name' => 'admin']);
$adminUser = factory(App\User::class)->create(['role_id' => $role->id]);
Which if needed in many tests can be done once in your tests setup() method and define your admin user as protected variable of your test class .
Keep in mind you should probably also use DatabaseTransactions; trait in your test class in order to remove any entries created by the commands above at the end of your tests.

Related

assertJson is not equal to expected to actual in laravel

I'm new in unit tests in laravel and currently facing an error on my test. Please see my code below.
Test
/** #test */
public function users_can_view_homepage_products()
{
$response = $this->get('api/products');
$response->assertStatus(200)
->assertJson([
'id' => 1,
'name' => ucwords($this->faker->words(3, true)),
'slug' => ucfirst($this->faker->slug),
'intro' => $this->faker->sentence,
'price' => number_format($this->faker->randomFloat(2, 100, 99999), 2)
]);
}
Controller
public function index()
{
return [
'id' => 1,
'name' => 'Airpods Pro (2021)',
'slug' => 'airpods-pro-2021',
'intro' => 'New and powerful airpods from apple.',
'price' => 12400
];
}
Error
The test fails because the content of the json is different to that being tested. You probably want to test that the structure is the same, rather than the content:
/** #test */
public function users_can_view_homepage_products()
{
$response = $this->get('api/products');
$response->assertStatus(200)
->assertJsonStructure([
'id',
'name'
'slug'
'intro'
'price'
]);
}

How Can Insert Password From Seed to database by bcrypt function my code are show delow

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
DB::table('users')->insert([
'role_id' => '1',
'name' => 'MD.Admin',
'username' => 'admin',
'email' => 'admin#gmail.com',
'password' => bcrypt(value:'admin')
]);
DB::table('users')->insert([
'role_id' => '2',
'name' => 'MD.Author',
'username' => 'author',
'email' => 'mahid#gmail.com',
'password' => bcrypt(value:'auth')
]);
}
}
change 'password' => bcrypt(value:'auth') to 'password' => bcrypt('password')

Laravel's db:seed is not inserting any record in database

I am using Laravel 5.6 and database seeder is not working. I am trying to insert 100 new data in my database but nothing is being inserted. No error is being shown and I don't know why php artisan db:seed is not working
Here's my DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$students = factory(App\Student::class, 100)->make();
}
}
Here's my StudentFactory.php
use Faker\Generator as Faker;
$factory->define(App\Student::class, function (Faker $faker) {
return [
'id' => $faker->unique()->numberBetween(1,1000),
'rfid_number' => $faker->unique()->numberBetween(1,1000),
'first_name' => $faker->firstName,
'middle_name' => $faker->lastName,
'last_name' => $faker->lastName,
'name_extension' => $faker->suffix,
'email' => $faker->safeEmail,
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'photo' => '',
'house_number' => $faker->buildingNumber,
'barangay' => $faker->streetName,
'city' => $faker->city,
'province' => $faker->state,
'zip_code' => $faker->postCode,
'birth_date' => $faker->date('Y-m-d'),
'birth_place' => $faker->streetAddress,
'gender' => 'Male',
'religion' => 'Roman Catholic',
'landline_number' => $faker->tollFreePhoneNumber,
'mobile_number' => $faker->tollFreePhoneNumber,
'father_name' => $faker->name,
'father_occupation' => $faker->jobTitle,
'mother_name' => $faker->name,
'mother_occupation' => $faker->jobTitle,
'guardian_name' => $faker->name,
'guardian_occupation' => $faker->jobTitle,
'guardian_address' => $faker->streetAddress,
'year' => $faker->numberBetween(1,6),
'section' => $faker->cityPrefix,
'created_at' => now(),
'updated_at' => now()
];
});
and it shows no error.
Use create() method:
$students = factory(App\Student::class, 100)->create();

Random select value on array factory Laravel

I had user migration:
$table->enum('type',['seller','buyer'])->default('seller');
I want when using ModelFactory how to get random value seller or buyer?
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'firstName' => $faker->name,
'lastName' => $faker->name,
'username' => $faker->unique()->username,
'email' => $faker->unique()->safeEmail,
'password' => md5('user123'),
'bio' => $faker->sentence(3, true),
'type' => ???,
];
});
Make use of randomElement method
'type' => $faker->randomElement(['seller', 'buyer']),
Laravel version >= 5.6
use Illuminate\Support\Arr;
$array = [1, 2, 3, 4, 5];
$random = Arr::random($array);
// 4 - (retrieved randomly)
"type" => Arr::random($array);
Just in case that anyone is looking for the answer of this question with newer version of Laravel and PHP, you can utilize the enum in PHP like so:
<?php
namespace App\Enums;
enum UserTypeEnum: string
{
case SELLER = 'seller';
case BUYER = 'buyer';
}
and then your factory will look like this:
<?php
namespace Database\Factories;
use App\Enums\UserTypeEnum;
use Illuminate\Database\Eloquent\Factories\Factory;
class TaskFactory extends Factory
{
public function definition()
{
return [
'firstName' => fake()->firstName,
'lastName' => fake()->lastName,
'username' => fake()->unique()->username,
'email' => fake()->unique()->safeEmail,
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password,
'bio' => fake()->sentence(3, true),
'type' => fake()->randomElement(UserTypeEnum::cases()),
];
}
}
And also if your type column is nullable you can have your seeder type like fake()->randomElement([...UserTypeEnum::cases(), null]) as well.

How can I maintain foreign keys when seeding database with Faker?

Below is my model factory.
$factory->define(App\Business::class, function (Faker\Generator $faker){
return [
'name' => $faker->bs,
'slug' => $faker->slug,
'address' => $faker->streetAddress,
'phone_no' => $faker->phoneNumber,
'mobile_no' => $faker->phoneNumber,
'email' => $faker->companyEmail,
'website' => $faker->domainName,
'latitude' => $faker->latitude,
'longitude' => $faker->longitude,
'location' => $faker->city,
'business_days_from' => $faker->dayOfWeek,
'business_days_to' => $faker->dayOfWeek,
'description' => $faker->text,
'user_id' => $faker->factory(App\User::class),
];
});
and This my database seeder class
class DatabaseSeeder extends Seeder
{
public function run()
{
factory(App\Business::class, 300)->create();
}
}
But when I execute php artisan db:seed ...it does not work..
What should be the workaround here..any help would be appreciated..
you can get all ids using pluck (lists is depricated for laravel >= 5.2)
$userIds = User::all()->pluck('id')->toArray();
and get a random id for FK column:
'user_id' => $faker->randomElement($userIds)
You may also attach relationships to models using Closure attributes in your factory definitions.
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
I just found the workaround .. I replaced
'user_id' => $faker->factory(App\User::class),
with
'user_id' => $faker->randomElement(User::lists('id')->toArray()),
and that solves the problem for now..

Resources