تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Introducing Dispatcher Class0:00

Today, I'm working on Laravel Mix, and as I was working on it, I ran into a little mistake where I kind of fell back into old habits related to testing, and I thought it would make for a good lesson. So let's take a look at this Dispatcher class. It's a simple event dispatcher. You instantiate it, you call listen, you listen for an event name, and then you give it a function that should be triggered. Then, when you call fire, it will find all handlers, or functions, that have been listened for, and for each one, it calls that function. And that's it.

Naive Listener Testing0:45

It's really, really good. I love it. All right, so if we wanted to test this, well, we might say, I want to test that it can listen for events. So we do that. I want to test that it listens for events. And we'll give our assertion t object. Okay, so now how would we do this? Well, we instantiate Dispatcher, and we call listen. So we could do that part.

Well, we instantiate Dispatcher, and we call listen. So we could do that part. Let events, and you can see that I've already imported it here. So I can say, create a new Dispatcher instance. Next, I can say, listen for some event, and then trigger some kind of closure here, some kind of anonymous function. Okay, but now here's where a lot of people get tripped up, including myself sometimes. If we want to confirm that that worked, well, you might think, well, it's attaching to this events object up here. So why don't we just assert that the events object has changed, right?

events object up here. So why don't we just assert that the events object has changed, right? So then you say, well, T, and then we'll do a deepEqual here. And basically, we're going to compare events.all to show you. We're going to call this all method that just returns the events. We're going to make sure that it looks the way we expect. So it should have a someEvent key, and then it should have an array of handlers. So let's do this. Why don't we let handler equals the anonymous function? And then down here, we'll update this.

So anyways, you continue on, and next you're thinking, well, I want to make sure that we can fire events. So let's say test that it fires events. So once again, we could new up our event dispatcher. But this time you're thinking, well, I'm going to set up the world. So let's just imagine that we have some events. So now you're thinking, well, I got to set up the world. So why don't we just update this events object? So you say events.events equals an object, and let's imagine we have something already in there.

So you say events.events equals an object, and let's imagine we have something already in there. And that will once again be equal to maybe a handler that we could create. Then we could say, well, if you fire that event, and we give it some data here, that can be anything we want, well, then I expect that handler to be triggered. So what we can do is we can pull in sign-in, which is a nice mocking framework. It works really well. So now I could say sign-in.spy, create a spy for me. And that way, our assertion could be, well, I expect that handler to have been called. Like so.

Why Implementation Tests Fail4:06

What if later you're refactoring, and you decide, well, you know what, events, that's going to be a dependency that we inject. Or maybe you'll even decide, we're going to use an array instead of an object here, and then we'll push objects to it. It doesn't matter. The point is, you should be able to organize this and set it up however you want, and it should still work, and it shouldn't cause the test to fail. But the problem is, now, if we make this change, it does fail. And it's specifically failing because, well, we asserted that the way it stores the event listener should look exactly like this.

Testing via Public API4:31

And it's specifically failing because, well, we asserted that the way it stores the event listener should look exactly like this. Or in other words, we're testing how this dispatcher is implemented rather than its public API. So instead, let's start entirely from scratch, and we'll say, well, what are we testing here? We're going to test that it can dispatch events. Notice we're being a bit more broad. We are testing the feature or the functionality. All right. So now we could say, well, yeah, given I have a new event dispatcher, and I listen for an

All right. So now we could say, well, yeah, given I have a new EventDispatcher, and I listen for an event, so we could say events.listen some event, then trigger a handler, and we'll do that once more. Well, if our code later fires that event, then as a result, we expect that handler to be called. So once again, we could update this to signIn, and finally say t.truthy handler.called. Okay. So it's a small difference. And by the way, let's bring that back to an object like we had before.

Adding Data Assertions7:03

Now what I mean about adding more specifics is you can see here that when you fire an event, you give it some data. Imagine you fire a UserSignedUp event and the data would be equal to the $user object. We do want to make sure that that data is passed to the listeners' handle function. Because right now, if I didn't have that, we don't pass it through at all, our test is still going to return green. So we want that to fail. That's important. So what we could do is say, $someData here, that can be any format we want, but I'm going to expect it to be called with $someData two times.

We just care that when we do finally fire that event, that our handler is triggered the appropriate number of times.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟