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

Why Add Tests0:00

Welcome back. Now in this lesson, I'd like to write some tests for these files just to make sure everything works. And especially when you're working with open source and you have files and classes that other strangers will be editing. Well, when they submit PRs, you really need a way to know whether or not their PR broke anything, right? And if you don't have any tests to prove that,

Testing Cache Key Trait0:33

So if we write some tests, yeah, not only do we make sure that everything works, but we get some automatic checking for future PRs from the community. Okay, so let's go ahead and create what would be the easiest one to do, the simplest start. Why don't we test a model that uses this trait? Okay, so we'll say tests/catchableTest.php. So class CatchableTest,

and we'll say catchable_test.php. So class CatchableTest, and that's going to extend PHPUnit\Framework\TestCase. Okay, so let's write our first test. How about this? It gets a unique cache key for an Eloquent model. Okay, so that means I need an Eloquent model instance, and that model needs to use the Catchable trait, right? And finally, I need to verify the returned value. Okay, good enough.

And finally, I need to verify the returned value. Okay, good enough. Let's get started. So it sounds like I need to create sort of like a dummy model instance. So I'm going to assume that I create a method here called make, and maybe our dummy type will be a Post. So just give me a Post and save it to the database. Next, that model needs to use the HasFactory trait.

So just give me a Post and save it to the database. Next, that model needs to use the Cacheable traits. Okay, that'll be connected up here. Here, I need to verify the returned value. Well, why don't we do this? Key will be model::getCacheKey(), and then we can do a simple assertion. And let me hide the sidebar, by the way. So how do we figure out what this should be? Well, remember the format we used.

So how do we figure out what this should be? Well, remember the format we used. It should be the model name followed by a /, then the ID of the model. In this case, it'll always be one. And then finally, the last updated at timestamp. So that means we could do this. assertEquals post 1 -, and then we'll do model updatedAt timestamp. And then we'll compare that against the key.

and then we'll do model->updated_at timestamp. And then we'll compare that against the key. Simple enough, right? Okay, so let's get rid of the comments. We don't need those. And in fact, yeah, let's just replace this with model->getCacheKey(). All right, does that make sense? So I'm going to create a Post. Now, we do have to write the code to allow for that.

So I'm going to create a Post. Now, we do have to write the code to allow for that when we don't have a full Laravel application here, but we'll figure that out. And then we'll say, well, when we call model getCacheKey, we expect it to follow this format. Okay, so let's go ahead and run phpunit. Ah, command not found. We need to pull that in. composer require phpunit --dev.

We need to pull that in. composer require phpunit for development only. There we go. Now I have vendor been in my path, so I can just say phpunit here. Okay, our first failure. Call to undefined method, catchable test, makePost. Of course, we haven't done this yet. So I'm assuming a number of classes will need a dummy Post to play around with.

So I'm assuming a number of classes will need a dummy post to play around with. So I'm going to do this. I'm going to create a TestCase class, and this will just be an abstract class that all of our tests inherit from. And we'll have that one extend PHPUnit\Framework\TestCase. Okay, so now here is where we will have makePost. That can, of course, be protected, and we know that we'll return a dummy post at some point.

That can, of course, be protected, and we know that we'll return a dummy Post at some point. So maybe we could do this. New Post, set the title, some title, and then save it, and then return it. Okay, so that means we need a dummy post stub to create. So we'll say post, but that does need to extend Illuminate\Database\Eloquent\Model. But we haven't pulled that in, right? So let's make sure that we require that,

But we haven't pulled that in, right? So let's make sure that we require that, and we only need it for testing purposes. So Illuminate\Database for development. All right, that looks good. So yeah, now if we go to our composer.json file, we are referencing that only for development. That means we have access to this class. So our little stub here is going to use, well, we're gonna have it use the cacheable trait,

So our little stub here is going to use, well, we're gonna have it use the Cacheable trait, lircache dolly cacheable. Yeah, this is just a simple Post stub that we will use for our tests. So now when we call makePost, we will new it up, we'll set a title, and we'll save it. But now you're probably thinking, well, save it with what? We haven't set up any database connection.

SQLite Test Database Setup4:56

well, save it with what? We haven't set up any database connection. We don't know what our database is. Is it MySQL? Is it SQLite? Good point, let's do that now. Now, whenever I'm making a package that needs to work against a database, yeah, I don't try to remove the database. Plenty of people will tell you to do that.

so that it can be as real life as possible. And trust me, if we use like an SQLite database in memory, it's incredibly fast. There's no reason not to. Okay, so let's do this. Let's do our setUp method. And here, as part of every test, we'll set up our database, and then I will also migrate any tables that we have. In this case, we'll just have a single posts table.

and then I will also migrate any tables that we have. In this case, we'll just have a single post table. Okay, so let's do this, setup databases. Now, how do we do this? Well, luckily, we pulled in the illuminate/database package, so we can make use of that here. And in fact, you can even make use of it for any non-Laravel package. So let's do this. I'm going to use Illuminate\Database\Capsule\Manager.

So let's do this. I'm going to use Illuminate\Database\Capsule\Manager. And yeah, we can just alias that to DB like you're used to. So now I could say $database equals a new DB, and then we just need to do some setup. For example, what kind of database connection do we wanna use? Typically, you go to your config/database.php file to review all those connections. But in this case, we're just gonna pass an array like this.

to review all those connections. But in this case, we're just gonna pass an array like this. Driver will be SQLite, and the database itself, well, we're gonna use this little ":memory:" keyword. And yeah, that's like a special keyword that says, we only want a database in memory. Okay, so we've added our connection, what else? We need to boot Eloquent. And then finally, we're gonna reference this outside.

We need to boot Eloquent. And then finally, we're gonna reference this outside. So we'll say, set as global. Yeah, pretty standard setup, especially if you're gonna write tests like this for your packages. All right, so we've set up our database and our connection. Next, I need to migrate the tables. And like I said, in this case, we only have a single table, posts.

And like I said, in this case, we only have a single table, posts. So this will be like your migration file. Let's create a table called posts. And the Blueprint for that will be what? Well, we'll increment the ID. And then this can be as bare bones as possible. So we'll say a string for the title. And then finally, we need timestamps. And that's it.

And then finally, we need timestamps. And that's it. Okay, so now we know as part of our setup, we will create a new database instance and run a migration to build up a post table in memory. Okay, so that takes care of that. Now we have a post table, we have a Post stub or just a general Post model. So we build one up and we save it to our database in memory, and then we return that.

So we build one up and we save it to our database in memory, and then we return that. So now if I switch back to my cacheable test, we're extending TestCase, but that may not work. Let's test this out. I'm gonna run phpunit and yeah, it fails. Class TestCase not found. Now we could require this at the top, but I just want this to be a global class for development. So here's what we can do.

but I just want this to be a global class for development. So here's what we can do. I can go to my composer.json file and then say autoload, but specifically for development only. And now I will say, I just wanna reference this classmap here and we'll point this to test/testCase.php. Does that make sense? For development only, I want to autoload that file

Does that make sense? For development only, I want to autoload that file so that it's available anywhere. Okay, so composer dump-autoload to refresh that file. And now if I run phpunit, we're onto another error, which means we resolved that. What do we have here? Missing argument two for assertEquals called in CacheableTest on line 13. Now I'm 13.

called in cacheable test on line 13. Now I'm 13. Yeah, it looks like maybe I accidentally removed that and pull that back. Okay, so let's run phpunit again. We've changed the error, which is good. Now in this case, you know what? It looks like we got it. I just accidentally set posts, the table name rather than the model name.

I just accidentally set posts, the table name rather than the model name. So if I run this again, we get green. So we know it works. For example, if we go to cacheable and we just return foobar, sometimes I do this just to make sure, did this actually work or am I doing something wrong? So I'm gonna force a failure. Yeah, we returned foobar, but we expected that.

So I'm gonna force a failure. Yeah, we returned foobar, but we expected that. So if we do it correctly and try it again, that works. So now our trait is fully tested. There's nothing else to do in that regard. So let's close that out and see what else we need to test. So if we come back, yeah, why don't we start working on testing this? And I think I'd like to do a couple of things differently. Right now we're just calling everything as static methods.

Testing Russian Caching Class9:48

And I think I'd like to do a couple of things differently. Right now we're just calling everything as static methods. You know what? I'd rather set up a singleton in this case. And also I think if we scan this, even though there's not many lines and it's not really a big deal to begin with, we're probably doing too much here. For example, the fact that we're calling this setup and teardown is kind of a clue that

or extract a different class entirely so that you can narrow down exactly what the method should do. So yeah, we call setup and it's like, we append to a keys array, we turn on output buffering, and then we figure out if we have something in the cache. So we're doing a number of things there. And the same for teardown. So we pull from an array,

And the same for teardown. So we pull from an array, we turn off output buffering and we fetch the results, and then we cache some data and return it. So that's why it's kind of difficult for us to think of a method name. Now, maybe the reason for this is it's doing too much. So instead, if we could extract a class, more of a, almost like more of a controller of sorts that can be responsible for stuff like this,

more of a, almost like more of a controller of sorts that can be responsible for stuff like this, well, then our RussianDollCaching class can be responsible for caching. Why is a RussianDollCaching class responsible for output buffering, right? Okay, well, with that in mind, let's write a test and see if we can refactor a bit. So within here, yeah, let's create test/RussianCachingTest.php.

So within here, yeah, let's create test/RussianCachingTest.php, or I'm sorry, we called it RussianCachingTest.php. And let's just steal a little bit of this and paste it in. Okay, so we have a RussianCachingTest, and then we can delete that entirely and start on a new test name. How about something as simple as this? It caches the given key. That's the main thing I want this to do. It's a class that will cache the key in a specific way.

That's the main thing I want this to do. It's a class that will cache the key in a specific way. So let's think, let's say, imagine we have a Post, which we do now. Well, if we were to cache that Post, so something like our instance, I haven't set this up, but we could say our RussianDoll instance, if we call cache and pass the post, and then we'll give it a snippet here, and this would come from the view, of course,

and then we'll give it a snippet here, and this would come from the view, of course, but I'm just gonna do a stub here. So I will say view fragment, like that. Yeah, if we call cache on that, that should take care of everything. So now our assertion could be something like this, assertEquals, or maybe I could do assertTrue instead. And that way I could append to the API. So our RussianDoll class,

And that way I could append to the API. So our RussianDoll class, and maybe I could say something like hasCached this post, and that should return true. Okay, so let's save that, and immediately we know we need a cache method and a hasCached method, and this will tell us. So if we run it, undefined variable doll, let's go ahead and create that. doll equals new RussianDoll();

let's go ahead and create that. $doll equals new RussianCaching, and let's use that at the top. Laracasts $dolly RussianCaching. And in fact, we might eventually change that to just cache instead, but it's okay for now. So if I run this, our next error is no method called cache. So let's begin tweaking this. New method called cache, come back. Next, we need a method called hasCached,

New method called cache, come back. Next, we need a method called hasCached, so do another one, run it again, and failed asserting that null is true, of course. Okay, so now when we call cache, we're gonna give it a key, or let's see what we did give it, in fact. We're giving it a model. So maybe what we'll do is give it either a model or a key, and we'll just figure out what the user gave us.

So maybe what we'll do is give it either a model or a key, and we'll just figure out what the user gave us. That way, you're a little more flexible. So we'll say key as well as the, why don't we call this fragment instead? Okay, so now, well, I could use the facade, but that's gonna be weird. For example, if we just were to use anything right here, it's gonna squawk. So if we run this, class Cache not found.

it's gonna squawk. So if we run this, ClassCache not found. So yeah, we're referencing a facade, but a facade is more linked to the Laravel framework itself, and in this case, we don't have that. So instead, why don't we inject the underlying Repository class for caching, and we'll use that instead. So we could do this, use Illuminate,

and we'll use that instead. So we could do this, use Illuminate, we'll do Contracts, Cache, Repository. And yeah, I just happen to know that contract name. Okay, so now I can set up our constructor, Cache, and I'll run a little macro to assign that here. Okay, let's grab that and put it below. Now we can inject it, which means here, we can replace basically all references, and let's just use multiple cursors here,

we can replace basically all references, and let's just use multiple cursors here, and we'll say this, cache, like so. All right, and in this case, it's squawking because we haven't yet used these. So let's fix that now. If we are to cache something, then we could say return this, cache, and we are gonna be using tags still, so we'll call that views,

and we are gonna be using tags still, so we'll call that views, and then we'll say remember forever. Give it the key, use the fragment, and then return the fragment. There we go. Now notice, because this is only doing one thing, we have an easier method name. So let's go ahead and run this, but it's still gonna fail, of course.

So let's go ahead and run this, but it's still gonna fail, of course. Yeah, in this case, we're not passing anything into the constructor, so it's failing. So that's our next step. Let's go into our RussianCachingTest, and yeah, right here, we do need to give it the repository. So, well, what I wanna do is this. Let's build up the repository, so I could say new Illuminate\Cache\Repository,

Let's build up the repository, so I could say new Illuminate\Cache\Repository, but yeah, if I wanna use this, again, that's in a special package. So let's pull that in for testing. composer require illuminate/cache --dev for development only. There we go. Okay, so now we have access to that class. But finally, the cache repository, well, that will need to know

But finally, the cache repository, well, that will need to know what kind of cache store we wanna use. So for example, do you want the array driver, or do you want memcache to Redis? In our case, array is perfectly fine. So I could say new Illuminate\Cache\ArrayStore. I don't expect you to know some of this stuff. When you have to work with it, you'll learn it,

I don't expect you to know some of this stuff. When you have to work with it, you'll learn it, but yeah, don't feel like this is just something you have to know off the top of your head. Okay, so we have our cache instance. We're gonna pass that through to our RussianCaching class. And now let's run this again, and we've changed the error, so we're making progress. Failed asserting that null is true. So at this point, we're calling a hasCached method,

Failed asserting that null is true. So at this point, we're calling a hasCached method, but yeah, we haven't written that yet. So let's see, hasCached the given key, and I'm just going to return this cache tags views, and then we'll say, do we have the given key? All right, let's run that again, and we get green. But you know what? Still, if we come back, notice that we're passing the model itself

Still, if we come back, notice that we're passing the model itself to each of these. That's just gonna stringify it basically. So why don't we do this? Why don't we check for both? So I'm gonna say post getCacheKey, and then pull that in down here, getCacheKey. So I expect that to return green, and it does. But also if I just say hasCachedPost,

So I expect that to return green, and it does. But also if I just say hasCachedPost, I want that to work as well. Okay, let's run that, and now this time it should fail. Okay, so we just need to do a quick check. So right here, we could say, if key is actually an instance of a model, for example, Illuminate\Database\Eloquent\Model, if you gave us a model, well, in that case, I'm gonna set key equal to getCacheKey.

if you gave us a model, well, in that case, I'm gonna set key equal to getCacheKey. So we're just gonna make that call for you automatically. So that way, if I come back and refresh, that works. Now let's do the exact same thing up here. So if I call cache, I can give it a string, or I can give it an Eloquent instance, and it will still automatically call that method. And what we might wanna do in the future is actually check to ensure that it has the method.

And what we might wanna do in the future is actually check to ensure that it has the method. We can get to there, but for now, this is fine. So let's run that again, or I'm sorry, let's make sure it failed. So run it, it fails, uncomment it, it passes. Now, in this case, we're doing it in two places. I don't worry about repeating once. It's when you get to like two repeats or more on where you wanna extract.

It's when you get to like two repeats or more on where you wanna extract. But yeah, if you wanted to extract, you could do this. You could say key equals this normalizeCacheKey, and then pass that in. So let's see what that would look like. normalizeCacheKey, and that will accept the key. And yeah, now we could take that out, and we could say if key is an instance of a Model, well, in that case, let's return a method call.

and we could say if key is an instance of a model, well, in that case, let's return a method call. Otherwise, let's just return the key, okay? So now down here, we could remove that, this normalizeCacheKey, and then I'm gonna do the same thing up here. All right, let's run it, and we still get green. So that worked. Now, based on our tests, we're starting to see that our main public API

Refactor into Blade Directive19:17

Now, based on our tests, we're starting to see that our main public API for this class is a method called cache and a method called hasCached. So what about some of this other stuff like setup and down here, teardown? Yeah, we're starting to see like they're not really related. This is more, like I said, sort of like controller type stuff where we turn on output buffering.

sort of like controller type stuff where we turn on output buffering. I don't want my Russian doll caching class to be responsible for output buffering. So instead, maybe we need an additional class that will almost serve as like our blade directive controller of sorts. So let's do this. Let's create it. This isn't where we will register the blade directive,

Let's create it. This isn't where we will register the Blade directive, but maybe that name's okay for now. I'm doing a lot of this on the fly, so we can always change it if we need to. So we'll set this to laracast/dolly in our Blade directive. And now here, we can still do setup and teardown because this is almost like our controller now, specifically for the directive, if that makes sense.

because this is almost like our controller now, specifically for the directive, if that makes sense. And here's what I mean. If we go back to our service provider, well now, I'm no longer gonna call that directly. I'm gonna reference our Blade directive here. And yeah, I think that should do the trick. However, we created public methods, but we're still referencing these as static methods. So this might be a good point to register a singleton

but we're still referencing these as static methods. So this might be a good point to register a singleton so that we can reuse that class over and over because we don't need multiple instances in this case. At least I don't think. So let's create a singleton. I'll just make this equal to the actual class path. And now that'll accept the app instance. And down here is however we need to register or instantiate the class.

And down here is however we need to register or instantiate the class. So yeah, we know that ultimately we will return a new Blade directive, something like that. And let's go ahead. We're in that namespace, so we don't have to do anything there. And in fact, what we could do here is this, blade directive class. Now, I know that we'll probably end up

blade directive class. Now, I know that we'll probably end up passing in a dependency here, but we'll leave it like that for now. And we'll get back to that. So that means we can update this section entirely to something like this, app, LayerCast, dolly, blade directive. So give me the singleton there and then call the given method here.

So give me the singleton there and then call the given method here. And let's see, what's squawking? So right here, we're not using app, like so. Okay, so does that make sense? We are registering a singleton. So that means every single time we pull this item from the container, we're getting the same instance each time. And then we're calling a setup method here.

we're getting the same instance each time. And then we're calling a setup method here and then a teardown method there. Okay, so now if we go back to our Blade directive, we now have a place to put some of the stuff that was oddly placed within the RussianCaching class. So for example, as I scroll up, for example, the keys right here. Well, let's just make that directive class responsible for storing those keys.

Well, let's just make that Directive class responsible for storing those keys. All right, let's go back, what else? If we scroll down, setup, let's take or delete all of that and put it in here. And then I know we will need to call this keys and that will accept the model. Okay, so we can delete that entirely. Next, we have cache, hasCache, that's all good. normalizeCache, here's our teardown.

Next, we have cache, hasCache, that's all good. Normalize cache, here's our teardown. So I'll delete all of that. And now this will go in here. We have a better place for that. Okay, so once again, let's update this to a keys property. Now we can take some of this specific stuff and just delegate accordingly like this. Let's set a constructor and we'll accept the RussianCaching class here.

Let's set a constructor and we'll accept the Cache class here. And I'll just call this cache and use a macro here to assign that. Now, right here, I can just say return $this->cache->hasCached(), and then we'll pass in the key. And why don't we turn on output buffering at the start? That's just a formatting thing. So we call setup, we turn on output buffering, we figure out what the key should be and we store it.

So we call setup, we turn on output buffering, we figure out what the key should be and we store it. And then we return a Boolean that just indicates have we cached this or not. And that's all our controller is doing at this point. Now for teardown, we pop this off, we turn off output buffering. Let's put that at the top for consistency. And now down here, once again, we can delegate this cache, but now we have the method as the same name.

And now down here, once again, we can delegate this cache, but now we have the method as the same name. So we might change that in a minute. But anyways, we're going to catch the key with the HTML. And now the specifics of how we tackle that can be isolated a bit. And now we can see we can clean this up further by inlining a lot of this. For example, array_pop the keys and then ob_get_clean and just do this.

For example, array_pop the keys and then ob_get_clean and just do this. And I'll even put that on the same line. Yeah, there we go. So that's what I mean when I say this is sort of like a controller or a traffic cop of sorts. So it is going to turn on output buffering, but then it's going to delegate and point to our RussianCache class and say, let me know if you've cached this item.

our Russian Cache class and say, let me know if you've cached this item. And then down here, it's going to say, please cache the HTML that I've been buffering right here. So now if we go back to this class, we can begin cleaning this up even more. So we scroll up. Yeah, this is actually quite a bit better in my mind. We have a method called cache that will cache an item accordingly.

We have a method called cache that will cache an item accordingly. And then we have a hasCached method. And that simply knows how to check if we have the given key or model cached and associated with this tag. So why don't we change some of these method names? Let's go with has and put to be a little more consistent. So we know that we'll need to go back to our test and then change this. So we'll say right here, has,

and then change this. So we'll say right here, has, and then down here, we'll say put. Next, we can change $doll to $cache. Okay, now if we go back to our Blade directive, let's refresh this. Right here, we can change the method to has, and then finally put to be a bit more consistent. Okay, let's run phpunit and see where we are. And we get green, so we know everything's working.

Functional Blade Directive Test25:22

Okay, let's run phpunit and see where we are. And we get green, so we know everything's working. Now, of course, we haven't yet written any tests for the Blade directive. Now, this is, like I said, kind of our controller. So this is where we will sort of write our functional test to make sure that everything's working. So that'll be our final step for this lesson. I'm gonna create a new file, blade_directive_test.php. And once again, I'm gonna swipe from here

I'm gonna create a new file, blade directive test.php. And once again, I'm gonna swipe from here and paste that in. Okay, so let's delete that. And what is our test here? What are we testing? How about, well, remember, if it's the controller, this is sort of like we're saying this sets up the opening cache directive. So how about it sets up the opening cache directive.

this sets up the opening cache directive. So how about it sets up the opening cache directive. So that means we need to new up the Blade directive class and then call the setup method on it, right? And then call the setup method, perform assertion. Then we're gonna call the teardown method and perform our assertions. And I think that's it. Okay, so new up the Blade directive class. Why don't we say directive equals this,

Okay, so new up the Blade directive class. Why don't we say directive equals this, createNewCacheDirective. And we'll create that, createNewCacheDirective. And let's see, we know we're gonna return an instance of BladeDirective, but as we've established up here, we need to give it the RussianCaching dependency. And further, if we take a look at that, that has a dependency of its own.

And further, if we take a look at that, that has a dependency of its own of the cache repository contract. So let's set this up. Let's do cache first. So we can say new Illuminate\Cache\Repository. And then that will need an instance of the ArrayStore driver. So new Illuminate\Cache\ArrayStore. Next, we need our Russian caching class.

So new Illuminate\Cache\ArrayStore. Next, we need our RussianCaching class. So RussianCaching, and then pass that through. And then finally, we will return a new instance of our BladeDirective class with the dependency. Okay, now if we scroll up, we have our directive. So we can remove that. Next, we call the setup method. So directiveSetup. And don't forget, the setup method needs a model.

So directive setup. And don't forget, the setup method needs a model. So luckily, we created a makePost method for this very purpose. So we can just pass that in. Next, perform an assertion. So what should happen when you call that method? Well, it turns on output buffering. It appends to a key. And finally, it lets us know

It appends to a key. And finally, it lets us know if we have the current key or model cached. Well, we know by default that should be false, right? So this assertFalse. And we'll say isCached. And then reference that here. Okay, next, call the teardown method. So directiveTeardown. And finally, what should happen at that point?

So directive teardown. And finally, what should happen at that point? Well, at that point, it should be cached and we should return the HTML fragment. But we don't have a fragment, so we can simulate that by doing just a simple echo statement. And because we have output buffering turned on, this will be fine. So I could do this.

this will be fine. So I could do this. Now, we call our teardown method that will return the cached fragment, or I'll call that, oh, that's fine, cached fragment, and then perform our assertions. Okay, so this assertEquals div fragment and compare that against that. Why don't we go ahead and run that? So phpunit test, BladeDirectiveTest,

Why don't we go ahead and run that? So phpunit test, Blade directive test, class RussianCaching not found. We need to import that. Laracast, dolly, RussianCaching. All right, run it again. What else? Class BladeDirective not found. We need to import that. Run it again.

We need to import that. Run it again. And it fails. So accessing static property keys as non-static. So let's go back and see if we missed anything. Yeah, right here, we need to remove the static keyword. All right, run it again. Okay, we're getting close. So expected that, looks like I forgot a closing bracket. Let's see, yeah.

So expected that, looks like I forgot a closing bracket. Let's see, yeah. So if I run that, we get green. That works, excellent. So does that make sense? We knew up our directive class. We call this setup method and we perform any assertions there. And then we call our teardown method and we make sure that the response matches up.

And then we call our teardown method and we make sure that the response matches up and finally, what we might wanna do is ensure that it was in fact cached, if you wanna do that. So let's see how we could do that. Right now, our cache class is isolated down here. So if we want, maybe we could just assign that to the current instance and that way we can access it.

maybe we could just assign that to the current instance and that way we can access it and do a quick assertion off of it. All right, so we're just assigning it to this test class and now I could do something like this. This assertTrue, this $this hasCached the given model. All right, let's run that and we still get green so we know it works. I hope that makes sense.

if I run my entire suite, we're getting green, but we have a lot more assurance at this point. We know that our trait works. We know that the RussianCaching class itself works. And then finally, if I refresh, we know that the little Blade directive controller thingy works as well. Now, if we go through the source, we have a specific class for our directive. Now the ServiceProvider sets up down here a singleton

we have a specific class for our directive. Now the service provider sets up down here a singleton and then when we register the directive, that's what we're returning. We are returning a call to fetch the singleton and then call a setup method as well as a teardown method. Next, we have a flushViews middleware that the user can reference. Hopefully we can get to a point where we remove that entirely,

Hopefully we can get to a point where we remove that entirely, but we haven't reviewed the process of maybe caching the template contents itself or doing an MD5 and then working that into the cache key. We haven't gotten there yet. And then we have a Russian caching class, which is quite a bit more clear now. Before it was doing a lot, but now we have readable method names.

Before it was doing a lot, but now we have readable method names that do exactly what we expect. So at this point, once again, do a git status. I'm gonna add everything and then commit with add tests and refactor. And now in the next lesson, we're gonna set up the package. So I will create a GitHub repo. We'll register this with packages.org

So I will create a GitHub repo. We'll register this with packages.org and then we'll start fixing bugs and trying it out in a fresh installation of Laravel.

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