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

Refactoring Test Text0:00

Now that our first tests are working, we are ready for refactoring. That's one of the things I really love about test-driven development. It gives refactoring the importance it deserves. It's part of every test now that we write. And after only focusing on making a test work, we can now just focus on making it clean, simpler, better in any way you want it to be. I want to start here with the pretty big amount of static text that we have here in our tests. Here, here where we checked this, here as well, and also down here. So I really like to use those specific texts that you then look for on a specific page because it's very good to read and very good to see if your test fails.

So I really like to use those specific texts that you then look for on a specific page because it's very good to read and very good to see if your test fails. But once my tests are passing, I like to use variables. So let's do this here. First course, then we have our second course, and then we have our last course. And now we can get rid of all those details here of the course that we create. Something like this, but the downside here now is that the test is failing now because our courses are now not released anymore. So this means we could, again, bring in here the release field, which you probably get when I regenerate the code here.

Adding Factory State1:21

So this means we could, again, bring in here the release field, which you probably get when I regenerate the code here. So this release field, we could bring it back in here, but there's also a better way to do this. Because here the release field is very important because we only want released courses here, but we can do this also with a factory state. So inside our CourseFactory, so I'm creating here a new public function called released. And as an argument, I might want to add a specific date myself.

so I'm creating here a new public function called released. And as an argument, I might want to add a specific date myself. So it will be a Carbon instance and it will be a date, and we want it by default to be null. So this means we don't have to pass anything in here. And then in here for a factory state, we need to return this state. And here we can now use a short closure here. Here we are getting the attributes, which we don't need. But what we want to do is here return an array, which then overrides our default arrays definition.

But what we want to do is here return an array, which then overrides our default arrays definition. So the definitions for our CourseFactory. And here we want to set released_at to our date. And if it's not given, I'm going to create a new one for just now, just to have a Course which was released. And the return type will be the factory itself. All right, looks good. So this means now for all of our courses here, I'm going to call now the new released factory state.

So this means now for all of our courses here, I'm going to call now the new released factory state. And let's run this again. And now it fails because we don't see courseA anymore. And that's because this is just a string, which is now not being used to create a new Course. So instead, we're going to now use our variable firstCourseTitle. Let's run this again. And something else is failing because the same goes for the description. Let's copy this here.

And something else is failing because the same goes for the description. Let's copy this here. And let's say here we want to see the description. And now we have to do this for course B and the others as well. So let's get rid of this. I'm just going to copy this here two times. And then here and here, we're going to use a second course. And here and here, we're going to use our last course. It seems we have named this third course, but I think last course is better.

It seems we have named this third course, but I think last course is better. All right, let's run this again. And now our tests are working. And you can see now that our test here is much cleaner because we don't have all the data which we have provided ourselves, which was good at beginning and to making our test pass. But now I think this is now a more cleaner way to do this. And especially because every time we write some text, it gives this text some purpose.

Cleaning Remaining Tests4:17

And especially because every time we write some text, it gives this text some purpose. And the new developer who comes here is going to read the text, of course. But actually, we don't care what the text is as long as we see the title, description, and this for all of the three courses. So let's move on now to the second course here. And here we do exactly the same. We get rid of this here. The first course is the one which should be released.

We get rid of this here. The first course is the one which should be released. So let's call the release method here like this. And then only let's give those courses a name. I always like it to be quite specific. So this is a released course. And this is a not released course like this. And we want to make sure that we see the released course title. And we don't want to see the not released course title. Is it working? Yes, it is.

And we don't want to see the not released course title. Is it working? Yes, it is. Now we can also get rid of the array here because we're only checking just one thing which will clean this test up a little bit more. Again, let's run it another time. Yeah, it's still working. And one last time here. Let's get rid of this array and this array. We're not specifying this here anymore.

Let's get rid of this array and this array. We're not specifying this here anymore. And we have our first course which is a released course with an E. And the next one is our newest released course. And which we want to see first, course B, which is the newest released course title. And second should be the released course title. So when we're now going to run this, it will fail. And the reason is, again, because those courses are not released.

So when we're now going to run this, it will fail. And the reason is, again, because those courses are not released. So let's add the released method here. And now we also need to define something different here because one should be earlier released than the other. So this is the newest released course. So maybe let's add here a specific date to override the one where we have defined it should be now. And let's set this to yesterday. So this is now released now and this is yesterday.

Improving Controller Ordering6:43

And let's set this to yesterday. So this is now released now and this is yesterday. I think this should be enough to make this test pass again. And it does. This looks good. All right, so what else can we improve? Maybe let's check our controller here. Yeah, so we've been using the orderBy method and then providing here a second argument. And here's also a nice orderByDescending method.

and then providing here a second argument. And here's also a nice orderBy method. So this means we don't need to provide this. And this is already way better to read because you don't have two arguments. And it's enough just to read this one because this is now very obvious what this does. Again, let's run our tests here. Okay, this looks good. Maybe let us run all of them just to be sure.

Okay, this looks good. Maybe let us run all of them just to be sure. Yeah, okay, good. And then back here, also something that I don't like here is this whereNotNull. Because if you read this, you come to this controller, PageHomeController. Okay, we want to get some courses. Starting with whereNotNull. And of course, it is not that difficult to understand,

Creating Eloquent Scope7:47

Starting with where not now. And of course, it is not that difficult to understand, but what are we doing here? We are grabbing all the courses which are released, very similar to what we did inside our tests. So why don't we use a better method here as well inside our application code? And very similar to factory states, we can use scopes with Eloquent models. So let's see how we do this.

we can use scopes with Eloquent models. So let's see how we do this. So I could go now to my Course model. And just start creating and adding here a new scope. But again, we are using TDD here. So this means we first need to create a test. And now let's think about it. We are now creating a new scope. The scope belongs to a model. So this now means we have to create a test for our model.

The scope belongs to a model. So this now means we have to create a test for our model. So let's create now a new feature test. For me, again, it will be a feature test because I'm storing something in the database. I'm going to call this. Maybe let's already put this inside a models directory. And let's call this CourseTest. Refresh database and use the test template. Yes.

Refresh database and use the test template. Yes. So what do we want to test? I want to test that when I use a specific course scope that we only get back released models. It only returns released courses for released scope. Yes. Like this. Then here again, I'm going to need two Course instances here. Factory::create, and another one.

Then here again, I'm going to need two Course classes here. factory, create, and another one. And let's make one to be already released. Like this. I'm going to import the namespaces. And now I want to act and assert again. And here's another first time that we're going to use the expectation API of test. So I'm going to expect that a specific value. In our case, I want to get some courses from the database.

So I'm going to expect that a specific value. In our case, I want to get some Course from the database. I want to use the released scope, which we don't have yet. And then I want to get them back. And this is going to give me a collection. And I want to make sure that this has a specific count of just one. We've created two Courses, but we only want to get one back because only one was released. And then the first one and the id, we want this to equal one. So that's because the first Course which we are creating.

And then the first one and the id, we want this to equal one. So that's because the first course which we are creating will be the first in the database. It will have the id of one. And we just want to make sure that we only get this back here. And this is very helpful with the Expectation API because it's very good to read. We expect that a specific value here has a specific count. And then we move on and say the first element of it, the id should equal to one.

And then we move on and say the first element of it, the id should equal to one. All right, let's run this test. Let's see what's happening. Here is called the undefined method released. Yeah, the scope which we want to use here is not yet given. So now let's get back to our course and create it. So this will be a scope. We're going to begin this method with scope and then the name of it, scopeReleased.

We're going to begin this method with scope and then the name of it, scopeReleased. What we're going to get here is an Eloquent builder instance. And we're also going to return a builder instance. And in that here, we are seeing that on the query, we're now going to use what we've been using in the controller. So let's copy this here. We want to make sure that we only get elements where not now for the field released. Okay, if we now get back to our CourseTest,

where not now for the field released. Okay, if we now get back to our course test, I think this should already pass. And it does. So phpStorm does not know about the scope. But again, I can use the generate helper code from Idea, which then helps to know about this released method. And now it does work. So now our IDE understands this. Okay, that's good.

Using Scope in Controller11:49

So now our IDE understands this. Okay, that's good. And again, this test is passing. But we still haven't used this yet inside our controller. So let's also switch this out. And use our release scope here. And I'm now going to run all of our tests just to make sure that still everything is passing. And it does. And I think now this is way better to read.

And it does. And I think now this is way better to read. Give me all the courses which are released and order it by the released_at field. Looks good to me. And with that, I think we have now successfully refactored our first real test. And I think it looks now much better and is way better to read. And since the tests were already in place

and is way better to read. And since the tests were already in place and the code was already working, it was much easier just to adapt the code and then just see if our tests are still passing. And yeah, this is the power of TDD and refactoring. And I hope you could see that too today.

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