Writing a basic test0:00
OK, you're really close to having PEST under your belt and being able to go out into your own projects and start using it without any problems. But there are a few other little utilities that I'd like to show you just to really improve your flexibility when using PEST. In order to show this off, I'm going to return to our terrible email address rule. And imagine we want to test a few things about this rule. So one thing I want to check is that we can actually run passes on this rule. So I'll head into this Laracast test that I've set up, and I'll say it can validate an email. Let's quickly add a body here.
an email. Let's quickly add a body here. So I'll say rule equals new ValidEmailAddress. And then we'll say rule passes, and obviously I pass it an attribute. So that's going to be email. And then I need to pass it some form of email address. So let's say me@you.com. Just something that it will actually pass with. And I can wrap that in expect and say that I expect it to be true. Now if we run into our terminal as usual and run php artisan test, you'll see that we have
Filtering tests in CLI1:02
And I can wrap that in expect and say that I expect it to be true. Now if we run into our terminal as usual and run php artisan test, you'll see that we have that here. It can validate an email. You'll see that currently we're running all of these tests here. What if we just want to run this one test? Well we can use a filter for that. So php artisan test, and then we can say --filter, and we can pass a filter. So LaracastTest, and that is going to run the single test. But there is another way you can limit which tests to run in PestPHP.
Grouping tests1:29
So LaracastTest, and that is going to run the single test. But there is another way you can limit which tests to run in PestPHP. Let's jump back into the editor. And I'm going to tag on a method to the end of this test. It's going to be the group method. And you pass the group method the name of the group you want to add this test to. Let's call this Laracasts. Once I've done that, I'll head back into the terminal and I'm going to say php artisan test, but I'm going to limit it to a group called Laracasts. And you'll see when we do that, we still only have this single test.
but I'm going to limit it to a group called Laracasts. And you'll see when we do that, we still only have this single test. The nice thing about groups is that you can include different tests from across different files. So if we're going to say our PestContactsTest, and if I head down to this test here, and I add the group on, so just at the bottom again, group Laracasts, and go back into the terminal and rerun php artisan test with our group defined as Laracasts, then we're actually able to run just these two tests. Another cool thing you can do with groups is exclude them from the tests. So let's imagine that any test in the Laracasts group makes an API call.
Another cool thing you can do with groups is exclude them from the tests. So let's imagine that any test in the Laracasts group makes an API call. Well, obviously, we don't want to run those tests every time we run the test suite in CI. So in order to do that, we can say php artisan test --exclude Laracasts. And when we do that, you can take a look. It's run every test apart from those two that we defined using the Laracasts group. Now another cool thing about Pest is if all of the tests in a test file use the same group, you can make use of the group method at the top of your Pest file. And again, you can just pass the Laracasts group.
you can make use of the group method at the top of your Pest file. And again, you can just pass the Laracasts group. And that means you can remove this group method from the end of each test in the test file. Again, php artisan test --group Laracasts, we still have two passing tests. But now we define Laracasts once at the top of the file, and any test in this file will automatically receive the group Laracasts. Now one thing we might want to do is improve the regex for this custom rule so that it actually works with more email addresses as we discussed in previous episodes. But we don't have time to do it right now, so we want to leave ourselves a little to
Creating placeholder tests3:41
actually works with more email addresses as we discussed in previous episodes. But we don't have time to do it right now, so we want to leave ourselves a little to do to come back to later. Well Pest allows us to do that by simply excluding the closure from a test. So we can say it has better regex support and can catch more email addresses. And I'm going to close off and I'm going to leave the closure completely. Now if we jump into the terminal again and run php artisan test, you'll see that it's automatically skipped that test. We still see it in our output, so we can see we have jobs to do, but it doesn't fail. It doesn't throw any problems.
We still see it in our output, so we can see we have jobs to do, but it doesn't fail. It doesn't throw any problems. It just tells us that we need to come back and implement that test. It even tells us that we have an incompleted test. So when you're first scoping out or building out a feature, I know many developers who like to actually start by just writing out all of their tests and then slowly working on implementing each one of them. Okay, another thing I want to show you. If we take a look at this isValidEmailAddress rule again, you'll note that if the value passed is not a string, we throw an InvalidArgumentException.
Testing exceptions with throws4:45
If we take a look at this isValidEmailAddress rule again, you'll note that if the value passed is not a string, we throw an InvalidArgumentException. How could we test this in PestPHP? Well first of all, let's write a test that says it throws an exception if the value is not a string. And then we'll open our test up with a closure. And I'm going to copy this rule up here. And first of all, I'm just going to make it throw an exception. So I'll call rulePasses, and instead of me at u.com, let's pass the number 1, for example. If I give this a group, as we have done before, and I'll call it current, and then I'll jump
So I'll call rulePasses, and instead of me@u.com, let's pass the number one, for example. If I give this a group, as we have done before, and I'll call it current, and then I'll jump into the terminal and run php artisan test --group current, you'll see that we do fail because an InvalidArgumentException gets thrown. Now if you're coming from phpunit, you'll be used to doing something like this, expectException, and then passing InvalidArgumentException as the parameter. If we jump back into the terminal and run the same test, you'll see that it does pass. So once again, Pest is built on top of phpunit. Pretty much any code that you would write in phpunit will work without any changes in Pest.
Pretty much any code that you would write in phpUnit will work without any changes in Pest. However, there is an alternate syntax in Pest for catching exceptions that I much prefer. See, the annoying thing about catching exceptions in a test in phpUnit is you have to do it at the top of your test. And that's annoying because all of our other assertions and expectations and checks take place at the bottom of the test. So if your eyes automatically skip past this first line, you often don't quite understand what's going on in the test. Well in Pest, we can chain a throws method onto the end of the test, and we can pass
what's going on in the test. Well in Pest, we can chain a throws method onto the end of the test, and we can pass the InvalidArgumentException as the parameter there. Once we've done that, I can remove the expectException method. Jump into the terminal, run php artisan test again, let's filter by our group, and there we have the exact same passing test checking for that InvalidArgumentException. The other cool thing we can do is actually provide the message that was thrown. So I'll copy this value here, and we'll head back, and as the second argument, I'm going to pass the value must be a string. And if we run the tests again, you'll note we still have a passing test, but just to
to pass the value must be a string. And if we run the tests again, you'll note we still have a passing test, but just to show you that's working, if I say int instead of string, for example, run the test again, it's going to fail because we didn't have the correct message. So that's a real simple way to be able to check for exceptions and exception messages and keep your tests ordered in a nice way so that your exception comes at the end of your test rather than having to define it at the beginning. So a slightly different syntax that you can make use of, but super useful in my opinion. Now, there's one more thing that I think you should know before starting out on your Pest route, and that is what if you want to skip a test?
Skipping tests conditionally7:38
Now, there's one more thing that I think you should know before starting out on your PEST route, and that is what if you want to skip a test? Skipping is useful in lots of cases. Perhaps you've not quite finished the test logic yet. Perhaps it's an annoying failing test that you want to fix, but you just need to get things pushed out to production for the time being, or perhaps it's something that's being deprecated. So you're skipping the test for now, and then later on, you'll completely remove it. Well, as you can probably guess by now, seeing as we've already appended throws and group to the test, there's also a skip method that we can append to our test, and the skip method
Well, as you can probably guess by now, seeing as we've already appended throws and group to the test, there's also a skip method that we can append to our test, and the skip method receives a Boolean condition, which is either a straight up Boolean or a closure, and then a message if you want to add a message. So for our first example, why don't we just skip with no condition, and we'll say we no longer want to test the exception. Once that's in place, if we run our tests again, you'll see that the skip took place, and in our console output, we get the reason we no longer want to test the exception. So that's skipping with a straight up message. What if we want to skip, but add some form of conditional check in order to determine
So that's skipping with a straight up message. What if we want to skip, but add some form of conditional check in order to determine whether we should skip or not? Why don't we do something like this? As the first parameter, we'll pass a call to getenv, and we'll check getenv for a variable called skipTests. And by default, that's false. So if we don't define it, it will automatically not skip the tests. Well, if we jump back into the terminal and run php artisan test --group=Current, we need to change this to string again, just to fix that issue.
Well, if we jump back into the terminal and run php artisan test, we need to change this to string again, just to fix that issue. But yeah, if we do that, you can see we have a passing test. But if I pass skipTests equals true, and then run php artisan test, you'll see that we're now skipping this test because this condition is now true. So yes, you can do conditionals. What if you want to do a conditional on something else? Something like a config in your Laravel application? If you try to write config, and let's do app.name is equal to foo. If you attempt to do that, and then run php artisan test, you're going to get an exception because config
If you try to write config, and let's do app.name is equal to foo. If you attempt to do that, and then run php artisan test, you're going to get an exception because config does not exist. The reason for that is that Laravel has not been booted by the time this condition is run. But PEST allows us to get around that limitation by passing a closure, which will only be executed after Laravel has been booted. So once we've done that, if we run php artisan test groupEqualsCurrent again, you'll see that this is passing. But if I go into my .env file and change the app.name to foo, and then come back and run it again, you'll see that we now skip.
But if I go into my .env file and change the app name to foo, and then come back and run it again, you'll see that we now skip. So that is skipping, grouping, catching exceptions, and even being able to create test to-dos in PEST php, and using that combination of utilities, you'll be able to very easily navigate and execute various tests in your application.
