-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Testing issue with Event::fake() on Eloquent models #18066
Comments
The above has been updated, adding Event::fake();
Model::setEventDispatcher(Event::getFacadeRoot()); |
I have a similar issue where Event::fake(); is stopping events triggering but the Event::assertDispatched is not being triggered even adding the code suggested above. When I remove the Event::fake() then the events are dispatched and broadcasting when phpunit is run, so I am sure that the events are triggering correctly. Pusher output from running phpunit with Events not being faked:
Code below:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Support\Facades\Event;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Components\Alcie\Alcie;
// Events
use App\Components\Alcie\Events\AlcieAddedEvent as AlcieAddedEvent
class AlcieApiTest extends TestCase
{
// Disable middleware
use WithoutMiddleware;
use DatabaseTransactions;
public function testUpdate(){
Event::fake();
Model::setEventDispatcher(Event::getFacadeRoot());
$alcie = Alcie::create(['alcie_type' => 'Test', 'parent_id' => 1]);
Event::assertDispatched(AlcieAddedEvent::class, function ($e) use ($alcie) {
return $e === $alcie;
});
}
} <?php
namespace App\Components\Alcie;
use Illuminate\Database\Eloquent\Model;
// Events
use App\Components\Alcie\Events\AlcieAddedEvent;
class Alcie extends Model
{
public $timestamps = false;
protected $primaryKey = 'alcie_id';
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'tblALCIE';
protected $fillable = ['last_update', 'alcie_type', 'description', 'last_update_by', 'parent_id'];
public static function boot()
{
parent::boot();
static::created(function($model)
{
event(new AlcieAddedEvent($model));
});
}
} <?php
namespace App\Components\Alcie\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class AlcieAddedEvent implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $alcie;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($alcie)
{
$this->alcie = $alcie;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('Alcie');
}
} |
@spirant what happens when you use the protected $events = [
'created' => AlcieAddedEvent::class,
]; |
Hi @dbonner1987. Thanks for the quick response. I have removed the static function boot() and replaced it with the protected $events property you have suggested - which is more elegant anyway, so I may continue to use this where possible ;-). However, I am still getting the same failure on phpunit. <?php
namespace App\Components\Alcie;
use Illuminate\Database\Eloquent\Model;
// Events
use App\Components\Alcie\Events\AlcieAddedEvent;
use App\Components\Alcie\Events\AlcieUpdatedEvent;
class Alcie extends Model
{
protected $events = [
'created' => AlcieAddedEvent::class,
];
public $timestamps = false;
protected $primaryKey = 'alcie_id';
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'tblALCIE';
protected $fillable = ['last_update', 'alcie_type', 'description', 'last_update_by', 'parent_id'];
} |
@spirant it does make your models a lot cleaner. The issue is actually in your callback that you pass to You need to use the $alcie property ( Event::assertDispatched(AlcieAddedEvent::class, function ($e) use ($alcie) {
return $e->alcie === $alcie;
}); |
Thank you for that. You are correct. I had tried many different versions of the return statement previously. However that was before finding this issue and the suggested Thank you once again for helping me sort this! |
@themsaid any reason for closing this without a resolution? I have a trait on my models that hooks into |
@joshbrw if you use Event::fake all your listeners won't be triggered and thus the effect you describe. |
@themsaid Yeah I get that. I guess that's the intended functionality? I just want to be able to assert some code is firing an event, but I guess I'll have to leave it. Thanks anyway! |
@joshbrw can you provide your test case? Have you tried adding |
@dbonner1987 yeah I tried that to no avail. I was just doing |
@davidianbonner Hi!
|
@chargoy answer is the only way I was able to perform tests in L5.6 for dispatched events. It used to work in older versions of Laravel in a different way. This needs to be fixed, it's silly to disable the database insert events when really we are generally testing for custom events such as image processing, send an email, notify additional platforms via Guzzle, etc... |
This has been fixed in #25185 which has been released in 5.6.34. |
I literally just had to implement @chargoy's hack solution the other day to get Event trigger tests working for an entity model. I'm using an Observer via Model::observe(). Did something regress? Using Laravel ^5.7.x (updating often). |
@guice The test which confirms that event dispatching works properly is still there and it's passing -> https://github.com/laravel/framework/blob/5.7/tests/Integration/Events/EventFakeTest.php Can you please take a look at it and see what are you doing differently so that the event doesn't get properly dispatched and executed? |
@X-Coder264 These lines: framework/tests/Integration/Events/EventFakeTest.php Lines 65 to 66 in f88917a
You're attaching the Note, order of operation: $initialDispatcher = Event::getFacadeRoot();
Event::fake();
Model::setEventDispatcher($initialDispatcher); Observer is attached in What happens if you flip the lines: Post::observe([PostObserver::class]);
Event::fake(NonImportantEvent::class); |
@guice I'll take a look at it and check what's going on sometime in the next couple of days when I'll have some free time. |
I'm using Laravel
|
@sevillaarvin I'm on L6 and I was getting:
|
To target model events, this works:
|
@jeromefitzpatrick Thanks for this information. However, I want to ask: please which part of the framework did you find that this is the construct of the name of the event dispatched? i.e. where you got the string I have checked the documentation and also I need it because I want to comment a part of my code with a link to how I got this. I would have loved to use the link to your comment as the "proof". Bu then some future version of Laravel may change this and I want to be able to follow such changes. Thanks |
@damms005 The logic for that is in static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
) |
Description:
I've been migrating some model events over to the new the object oriented
$events
array and noticed that any associated tests are failing using the new Event mocking helpers.After some poking around, it appears the Model dispatches on
Illuminate\Events\Dispatcher
instead ofIlluminate\Support\Testing\Fakes\EventFake
is it set in the boot method of theDatabaseServiceProvider
.I've found two ways to correct this:
AddingEvent::fake()
to thecreateApplication
method before returning the $app; orModel::setEventDispatcher(Event::getFacadeRoot());
afterEvent::fake()
.Perhaps one of the above need be mentioned in the documentation? Though, from the point of view that
Event::fake()
should make testing events easier – should instances of the event dispatcher be replaced or is was this the intended behaviour?Steps To Reproduce:
A simple example:
The text was updated successfully, but these errors were encountered: