Introducing Arch plugin0:00
Okay, come on, I know you've done it before, you've come up with this awesome new feature, you ship it, and everything starts breaking. And when you take a look at the error logs, you realize you've gone ahead and left a dump or you've gone ahead and left a rake all in there, or something like that, and problems start popping up. So how can you prevent that from ever happening? How can you prevent those issues from ever causing a problem again in the future? How can you also enforce a consistent architectural style within your application? Well, in PES V2, there is a brand new plugin called the Arch plugin which allows you to do just that. Why don't we dive in and we'll take a look at how you can get started. You don't actually need to install anything to work with the Arch plugin, it's built in out of the box. All you have to do is create a new file. I'm
Creating ArchTest file0:50
how you can get started. You don't actually need to install anything to work with the Arch plugin, it's built in out of the box. All you have to do is create a new file. I'm going to create a file in my feature directory, and we'll call it ArchTest. Now architecture tests work the same way as any other test in PHPUnit. So it starts with one of the test functions like it, and we'll say does not use debugging functions. And then we'll obviously open up our test closure, and I can write expect, and I can pass in here a function or an array of functions that I want to introspect, that I want PHPUnit to check my codebase for. So I'll do an array because I'm testing multiple debugging functions, and I'll just type as strings the names of those functions. So dump and die is one of them. dump would be another. array is another. Once I've done that, I need to chain on the next part of the expectation.
Asserting no debug calls1:39
strings the names of those functions. So dump and die is one of them. Dump would be another. Array is another. Once I've done that, I need to chain on the next part of the expectation. And here we want to check that they are not used in the application. So that's as simple as using the not statement that you're used to in PHP, followed by the toBeUsed method, which the architecture plugin adds. And that is all you have to write to test that those functions are not used anywhere in your codebase. In fact, why don't we give it a run and see what happens? Now, obviously, I could filter down to that test, or I could use one of the other methods that I showed you in the previous episode. But there is one more flag that I think you'll really like. If I type git status, you'll see that obviously the only file I've modified is that archTest.php file. And there is a flag called dirty in
Running tests with --dirty2:25
one more flag that I think you'll really like. If I type git status, you'll see that obviously the only file I've modified is that arch_test.php file. And there is a flag called dirty in Pest V2, which will only run modified test files. So I can say pest --dirty. And all of a sudden, it's going to automatically run only that single test file. So that is an incredibly useful feature when you're just changing one or two tests, and you want to make sure that they run correctly without needing to filter or do anything else. Add the dirty flag. Okay, you can see everything is passing. But what would happen if we go back into our code and add dump and die or dump or ray somewhere into our codebase? Let's jump into the ContextController here. And perhaps in the index method, I will dump and die the results of this Inertia render. So maybe we've done this during the debugging.
jump into the ContextController here. And perhaps in the index method, I will dump and die the results of this Inertia render. So maybe we've done this during the debugging stage of building the application, we want to check what the actual result is, jump back into my tests, and let's rerun pest --dirty, you can see that it fails. And it tells us that it was expecting dump and die not to be used in the ContextController. But obviously it was. From there, it's a simple matter of going back into our code and removing the dump and die. If I do the same with dump or ray, I would get obviously a very similar error just with a different name. So it's incredibly easy to add this architecture into your test in order to make sure that everything stays clean going forwards. You don't need an extra tool to do this work. Pest v2 has you covered. Now just to stop and say at this
Higher-order architecture tests3:58
your test in order to make sure that everything stays clean going forwards. You don't need an extra tool to do this work. Pest v2 has you covered. Now just to stop and say at this point, tests like these are a perfect use case for higher order tests, because we're not reaching into Laravel at all, they're very much self contained. So we can make them much simpler by removing the test closure entirely and chaining expect not to be used directly onto the end of the test like so and you can see if we rerun Pest dirty, everything still passes as expected. Alright, what other architecture tests might we want to include in our application? Well, let's take a look at our OrganizationController because we're starting to see a little bit of inconsistency in code here. You'll note that in certain cases such as in this store, we use the route helper. In other cases, we use the redirect.
Enforcing redirect consistency4:45
starting to see a little bit of inconsistency in code here. You'll note that in certain cases such as in this store, we use the route helper. In other cases, we use the redirect back facade. In other cases, we use the back helper. And here we use the redirect back facade again. So it would be good to have a consistent approach to redirecting the user to use one of these methods rather than a mixture of all three. This is a perfect use case for the arch plugin. First of all, obviously, we need to decide on which way we want to use. And in our case, I think using the redirect facade might be our best option. So we want to make sure you can't use the back function. We want to make sure you can't use the route function. And we'd also want to make sure you can't use the redirect function either. So let's make sure that happens by creating another test in our arch test file.
route function. And we'd also want to make sure you can't use the redirect function either. So let's make sure that happens by creating another test in our ArchTest file. It uses the redirect Facade for redirecting. And we can chain on expect. And here we could say redirect and there's the redirect Facade. And I could bring that class in. And I could say toBeUsedIn. And then I could say, in this case, for example, I want to check that ContextController. And if I rerun these tests, now, you should see, yes, everything still passes, it uses the redirect Facade for redirecting. However, that doesn't actually solve our use case. And it's very, very, very specific. So maybe instead, what we want to check is that those helper functions are not used inside our controllers. So why don't we list those helper functions in much the same way we listed dump and die and dump and Ray, we can say expect back and redirect and toRoute
are not used inside our controllers. So why don't we list those helper functions in much the same way we listed dump and die and dump and Ray, we can say expect back and redirect and to route not to be used in and then we can pass a partial for all of our controllers. So app, HTTP controllers. And let's close that test off and rerun. And hopefully, you'll see that this fails. It does. You can see expecting array not to be used in app HTTP controllers, but it is being used. So there is our problem. Let's go ahead and fix that by consistently using the redirect facade. So here, I'll update to route to be redirect()->route. And down here, I'll update back to be redirect()->back. And I think that's all of the use cases. So let's now rerun that test. And boom, everything's passing. Okay, here's a cheeky little fun one just to get you thinking outside of the box. What if you're the type of person who hates facades, you cannot stand facade, you don't want
Banning facades by namespace7:50
everything's passing. Okay, here's a cheeky little fun one just to get you thinking outside of the box. What if you're the type of person who hates facades, you cannot stand facade, you don't want them to use you want dependency injection everywhere. And if you can't use dependency injection, it shouldn't be done. Well, it's incredibly easy to write that test case as well. Let's start with it cannot use facades. And we'll chain on expect and we want to use the namespace where the facades are stored. So in our case, it's going to be Illuminate\Support\Facades, like so. And we'll just say not to be used. Now when I run this test, you're going to see that I get a failure. And that's because pink CRM is chock block full of facades. But then again, this wasn't to show you that pink CRM shouldn't use facades, it was to give you an indication of how you might start using the arch plugin in order to achieve your desired architecture for your use
