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

Refactoring Test Location0:00

Now, we have this test within the features directory, but if you review any of the methods, we're basically creating a model factory, we're calling a method on Article, and then we're performing an assertion. So this really isn't an outside-in test. I think of it more as a model test. With that in mind, I'm going to move it from the feature directory to unit. Now, I use the term unit a bit loosely. I think of it more as a model test. Next, I will rename this to simply ArticleTest. Okay, great.

Writing Outside-In Feature Test0:27

Next, I will rename this to simply articleTest. Okay, great. So now, I want to take another pass, but this time we'll approach it from the outside-in. Now, usually, I'll do this first, but in this particular case, I wanted to focus on the core API first. Okay. So now I'm going to call it articleRatingTest, but you'll see it's going to be a little bit different. Let's refresh database, and we'll say it can be rated. So this time, rather than calling methods on article directly, we're instead going to

Let's refresh the database, and we'll say it can be rated. So this time, rather than calling methods on Article directly, we're instead going to approach it the way any User visiting your system might. For example, given we have an Article, and I rate that Article a five, then the Article's rating should be five. Very simple. All right, let's get started. So I'm still going to construct the world, and that world is we have an Article. And actually, we should say, given I'm signed in. So given I'm signed in, and we have an Article, and I rate that Article a five, then the Article's.

And actually, we should say, given I'm signed in. So given I'm signed in, and we have an Article, and I rate that Article a five, then the Article's rating should be five. Okay. So we're going to not call article->rate, because we're no longer testing the model itself. I'm instead testing the whole system, starting with the endpoint. So if I make a POST request to, what would it be, articles/ and then the article's ID, and then /rate, ratings, rate, how about that? I think that's fine. And let's shorten that.

I think that's fine. And let's shorten that. Okay. So if I hit that endpoint in the same way we would submit a form, if I set the rating to five, then ultimately at this point, the Article's average rating should be five. So we can do this by visiting a page and expecting to see the rating. In this case, though, I'm just going to look in the database. So we'll say Article should have a rating of five. Okay. So notice just a little bit different in this case.

Okay. So notice just a little bit different in this case. And actually, we need to set the authenticated user. So this will once again be a factory for a User. Okay. So we're acting as some random User, and given we have an Article, well, if I hit the endpoint to rate that Article a five, then the current average rating should be five. All right. So we give it a run, and it looks like we need to import. So let's do this, actually.

Adding Rating Route3:01

So temporarily, I'm going to disable exception handling and give it another run. Okay. So now we get a not found HTTP exception, which means there is no route. All right. We'll go to routes/web.php, and I'll set it up here. Listen for a POST request to articles, and then an article wildcard. So we'll use route model binding to track down that article automatically. And then rate, and this will hit an ArticleRatingController and a store method on that. Okay. So now if I give it another run, that controller does not yet exist.

Creating Rating Controller3:31

Okay. So now if I give it another run, that controller does not yet exist. So let's create it. php artisan make:controller ArticleRatingController, and I'll run it again. Okay. Now that store method does not exist. All right. Right here. And that will accept the article in question. All right.

And that will accept the article in question. All right. Run it again. And now we're back to that main error. So we haven't done anything yet. So the current rating is null. There are no ratings. Okay. Well, at this point, it's just like the last episode. I can say articleRate, and rather than hard coding it this time, we're going to look in

Enforcing Authentication4:49

Okay. Let's give that a run. It fails. So I'm getting a 500 error. Let's see what that issue is. So we'll disable graceful exception handling. Run it again. Ah, okay. It's trying to rate the Article, because at no point do we declare you must be signed in.

It's trying to rate the article, because at no point do we declare you must be signed in. Okay. We can do that right here for now. Middleware, off. And run it again. Okay. Now it fails again, but for a different reason. So we expect to be redirected to the login route, but this is a brand new app. We don't even have that.

So we expect to be redirected to the login route, but this is a brand new app. We don't even have that. So I'll just very quickly say php artisan make:auth to generate all of those stubs and the views and the routes. We're not even going to use it, but it should create the necessary routes. Okay. So now if I run it again, we get the authentication exception, and this is what we want. So if I now turn off exception handling and run it again, we get green. Perfect. Now sometimes what you might want to do here, if you want an extra layer of protection,

Perfect. Now sometimes what you might want to do here, if you want an extra layer of protection, honestly, I think this is fine, but if you want to be extra secure that even if you're redirected to the login page, we do not want any rating in the system. Well, at this point we could say assertEmpty and then say, give me the article->ratings collection because at this point there should be zero ratings. So we know that's going to pass. It's a bit redundant, but again, it just gives you that extra bit of assurance. All right. So now we know it cannot be rated by guests, but it can be rated by authenticated users.

Adding Rating Validation6:14

All right. So now we know it cannot be rated by guests, but it can be rated by authenticated users. Next, let's handle validation. It requires a valid rating. Okay. So now let's say you're signed in and you have an Article and you tried to rate it, but for whatever reason, somebody's toying around with the form or they submit a curl request from the terminal, whatever reason, they don't give us a rating at all. If that's the case, we're going to expect the session to have errors. So assertSessionHasErrors for rating because he didn't give us a valid rating.

If that's the case, we're going to expect the session to have errors. So assert session has errors for rating because he didn't give us a valid rating. Okay. So I'm going to give that one a run. Session is missing the expected errors. Of course it is. So we'll come back and we'll say right here, I need to validate the request. And for the rating, well, that should be both required. Actually, let's stick with that and then we'll move on. So if I run it, that does return green, but yeah, I want to do one more here.

Actually, let's stick with that and then we'll move on. So if I run it, that does return green, but yeah, I want to do one more here. So yes, if I don't provide any rating at all, there should be errors in the session, but if I do it one more time and we provide a rating, but something of the incorrect type, so like foo. All right. Well, exact same thing there. So we'll give that a run. And now this one is failing because if we switch back, yes, he gave us a rating, but we didn't do any validation to ensure it's of the right kind and of the right value.

And now this one is failing because if we switch back, yes, he gave us a rating, but we didn't do any validation to ensure it's of the right kind and of the right value. So let's just say it needs to be in this list. You can star an article one through five. So now if I give that one a run, we're back to green. Okay. Anything else? What about if we switch back here? So yes, it can be rated, but we can also update the User's rating. So let's just copy that whole thing and we'll say it can update a User's rating for, actually,

Updating Existing User Rating8:00

So yes, it can be rated, but we can also update the user's rating. So let's just copy that whole thing and we'll say it can update a user's rating for, actually, that's fine. It can update a user's rating. So given we have a signed in user and we have an article, if the user tries to rate the article, maybe they select five stars. Okay. Well, at this point, the rating should be five and we already know that works. However, if they later try to rate it again and this time they select one stars, okay, well, the average rating should not be three, in this case, five plus one divided by two.

However, if they later try to rate it again and this time they select one stars, okay, well, the average rating should not be three, in this case, five plus one divided by two. It should be one because we're updating the current User's rating. So let's run that. And we already had a model test from the previous episode to ensure that works. But once again, it can be useful to represent the same action at different layers. So this is looking good. We have some tests to confirm how all of this should work. So if everything is passing, and it is, in the next episode, we'll switch over to the browser and set up the component to make all of this work.

So if everything is passing, and it is, in the next episode, we'll switch over to the browser and set up the component to make all of this work.

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