How with $faker->word get unique value? - laravel-5

In laravel 5.8 app I make tests and adding new user for any tests I encountered that line
$loggedUser= factory(User::class)->create();
raise error :
Doctrine\DBAL\Driver\PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'Username pariatur' for key 'users_username_unique'
with factory defined :
$factory->define(App\User::class, function (Faker $faker) {
$username= 'Username ' . $faker->word;
return [
'username' => $username,
I do not clear database, but how to make in series of tests get unqiue word for any test?

Faker provides three special providers like unique(), optional(), and valid(), to be called before any provider.
//use unique() before calling the method
$faker->unique()->name;

Related

Testcase creating duplicate entries and deleting mysql database entries when tests are configured to use sqlite

I'm trying to seed my tests with data using the TestCase
TestCase.php
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected $roleOwner;
protected function setUp(): void
{
parent::setUp();
$this->roleOwner = factory('App\Role')->create();
$this->roleCounsellor = factory('App\Role')->create([
'name' => 'counsellor',
'display_name' => 'Counsellor',
'description' => 'Counsellor on team.'
]);
}
protected function tearDown(): void
{
parent::tearDown();
}
}
RoleFactory.php
$factory->define(Role::class, function (Faker $faker) {
return [
'name' => 'owner',
'display_name' => 'Owner of Team',
'description' => 'Owner of users team.'
];
});
When I run all of my tests vendor/bin/phpunit I get this error for dozens of tests:
Tests\Feature\UsersTest::a_user_can_remove_a_counsellor_from_their_team
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'owner' for key 'roles_name_unique' (SQL: insert into roles (name, display_name, description, updated_at, created_at) values (owner, Owner of Team, Owner of users team., 2020-07-07 19:59:43, 2020-07-07 19:59:43))
Caused by
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'owner' for key 'roles_name_unique'
When I run each test individually everything passes.
Also, when I run all of my tests it deletes everything in my mysql database, and I have my tests configured to run on sqlite. I think that's related, but I'm not sure.
You have to make sure that the database will be reset after each test. I think the RefreshDatabase trait is what you are looking for. See the docs.
If you are not using in-memory database in your unit tests then the above trait can running very long time. So you can use the following trait Illuminate\Foundation\Testing\DatabaseTransactions. It will run much faster because it does not have to reset the database for each test. It wraps every test in a database transaction and rolls it back afterwards. That way, no actual changes will be written to the database.

Why last id is lost while creating process?

I have a create method that works fine, but it fails trying to create its relation:
public function create(array $article, string $note)
{
$art = $this->article->create($article);
print($art->id) // this line is for helping me to know if id is successfully generated. It works!
$this->article->note()->create([
'article_id' => $art->id, // the id desapears
'note' => $note
])
}
Console logs:
Integrity constraint violation: 1048 Column 'article_id' cannot be null (SQL: insert into notes (article_id, note, updated_at, created_at) values (?, TESTING, 2019-11-13 13:03:07, 2019-11-13 13:03:07))"
The field article_id is probably not a fillable attribute on the Note model.
You could also create the note like this, without adding article_id as a fillable attribute:
$art->note()->create([
'note' => $note
]);
Also make sure that the relations are defined correctly on the models. If an article can have many notes, there might be something wrong with your definitions, since note is currently singular. If it is a one to one relation everything might be fine.
You need to save your article. $art->save()

How to mock a many-to-many relationship in Laravel unit tests

I have the following tables, users, roles and role_user which creates the many-to-many relationship.
In my UserFactory when creating users I assign them the basic role of 'user' like so:
$factory->afterCreating(User::class, function ($user, $faker){
$roles = Role::where('name', 'user')->get();
$user->roles()->sync($roles->pluck('id')->toArray());
});
And then in my unit test I can test for users that they are redirected with a 302 when trying to access admin pages:
$this->actingAs(factory(\App\User::class)->make());
$request = Request::create('/admin', 'GET');
$middleware = new AccessAdmin;
$response = $middleware->handle($request, function () {});
$this->assertEquals($response->getStatusCode(), 302);
This works as expected but the problem is testing the reverse of this with an admin user as I'm unsure how to mock the relational data. I have tried creating the user and then attaching the roles like so:
$user = factory(\App\User::class)->make();
$roles = Role::where('name', 'admin')->get();
$user->roles()->sync($roles->pluck('id')->toArray());
This gives me the following error:
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048
Column 'user_id' cannot be null
This is correct because the user is never created in the DB so the user has no ID.
How do I mock the user/role relationship?
Are you sure you want to mock the relationship?
Instead, I would recommend recommend using DatabaseTransactions trait in your Test file, and create() method instead of make() for your factory.
use DatabaseTransactions;
....
$user = factory(\App\User::class)->create();

Error inserting a record using Laravel Cashier and many-to-many relationship

I have a many-to-many relationship between the User and Subscription tables in Laravel, as follows:
In Subscription.php:
public function users()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
In User.php
public function subscriptions()
{
return $this->belongsToMany('App\Subscription')->withTimestamps();
}
I create a new subscription in Cashier (using Stripe) as follows:
$user->newSubscription($planname, $planname)->create();
(Note that the product and plan names are currently the same and the user's card is on record, hence the lack of a stripe token.)
But when I run this I get an error:
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into subscriptions (name, stripe_id, stripe_plan, quantity, updated_at, created_at) values (projects, sub_EY1zRywZ1jUjLl, projects, 1, 2019-02-17 20:07:36, 2019-02-17 20:07:36))
I'm not sure if the relationship is causing the issue or whether it's my new subscription code. How do I fix this error?
UPDATE:
I've made the following change and I still get the same error:
$user->newSubscription($planname, $planname)->create(null,[
'user_id' => $user->id,
]);
UPDATE 2:
I've made the following change and the exact same error still occurs:
$id = Auth::id();
$user = User::find($id);
// $user = Auth::user();
Do you have the Billable trait added to your User model?
General error: 1364 Field 'user_id' doesn't have a default value.
According to this, I think you need to fill the user_id column with an id value via $id = Auth::id();
Taken from laravel documentation:
Additional User Details
If you would like to specify additional customer details, you may do so by passing them as the second argument to the create method:
$user->newSubscription('main', 'monthly')->create($stripeToken, [
'email' => $email,
]);
UPDATE
Could you try this one:
$id = Auth::id();
$user = User::find($id);
$user->newSubscription($planname, $planname)->create();

Laravel Factory Can't Save Relation

I use Laravel 5.6, and I have a problem with my seeder.
I use this :
factory(\App\Models\Merchant::class)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$m->stores()->save(factory(\App\Models\Store::class)->create()
->each(function ($s) {
$s->products()->save(factory(\App\Models\Product::class, 10)->create());
})
);
});
All are hasMany relations.
Doing this, I have this error :
General error: 1364 Field 'merchant_id' doesn't have a default value
(SQL: insert into stores ....)
It's like my first $stores->save( ... ) doesn't use the merchant created.
In my DB, I have one merchant created.
If I use ->make() instead of ->create(), it works for the Store, but I can't save products because it's not persisted...
Is it possible to use multiple save in factories like this ?
Your code may need a little refactoring as you may be chaining creation of models incorrectly:
factory(\App\Models\Merchant::class, 2)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$store = factory(\App\Models\Store::class)->create(['merchent_id' => $m->id]);
factory(\App\Models\Product::class, 10)->create(['store_id' -> $store->id]);
);
});
Note: In order to use the ->each() method, you need to have a collection instance. I do not think creating only one merchant will return a collection. In the example, we create 2 merchents.

Resources