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

Testing Best Buy API1:20

So you've got to use a lot of techniques. All right, but anyways, I already have an account with Best Buy. I have a key. So if we go to Getting Started, and get your key here, and then if we scroll down, you want to make a cURL request to this endpoint. And notice you've replaced the SKU with the product you're querying. And that will return the product details. So for example, if I were to grab this, and let's go to php artisan tinker. I'll paste that in. Here is the URL.

That's the SKU. So let's see if we can make this work. Fetch product information about this SKU and the API key. So yeah, if we were to say, Illuminate\Support\Facades\HTTP, and we're going to make a GET request to that URL. And then I want the JSON results. Let's give this a run. And sure enough, it says easy as that. So now we can see, all right, what is the current sale price? Let's see if we can find if it's available.

So now we can see, all right, what is the current sale price? Let's see if we can find if it's available. I thought it was availability. There it is. online availability. Yeah, so they have two different ways to track it. If it's available in-store or online. We're only going to stick with online for now. So we want the keys online availability, and then we want the sale price. So for example, we could say product, and then we could check out product online availability.

Storing API Key2:48

So we want the keys onlineAvailability, and then we want the salePrice. So for example, we could say product, and then we could check out product onlineAvailability. Run it. It is currently not available. But if we get the salePrice, it's $299. And I think we're all set to go. So I'm going to do a couple things. I'm going to grab that API key. And my first step will be to store it within an .env file. And I'll call it BEST_BUY_API_KEY.

And my first step will be to store it within an environment file. And I'll call it Best Buy API key. And I'll paste that in. Next, I'm going to hold on to this

Creating Client Test3:45

And to do that, you got to make a real request. It's the only way to ensure it works. Because think about it. What if down the line, they change their response? And if they do, and you don't track it, well, it's going to break your code, right? And you're not going to know about it. So we do need some tests that make real HTTP requests. And let's do this. We'll add a new directory for our clients. And then within here, we'll add a PHPUnit test.

We'll add a new directory for our clients. And then within here, we'll add a phpunit test. And we'll call it BestBuyTest. And then a test class to match. Next, notice we are extending PHPUnit\Framework\TestCase. But I'm going to work with Laravel, so I actually want to extend our project TestCase. So that has a namespace of tests\TestCase. Finally, we will refresh the database as needed. And we'll say it tracks a Product. Okay.

And we'll say it tracks a product. Okay. How do we make this work? Let's write it out. Given I have a product with stock at Best Buy. If I use the Best Buy client to track that stock, it should return the appropriate stock status. Yeah, I mean, that's basically it. Okay, let's get started. We're going to seed the database with our retailer with ProductSeeder.

Okay, let's get started. We're going to seed the database with our Retailer with ProductSeeder. All right, let's have a look at that. So we're assuming Best Buy here, which is fine. But of course, we can always make that configurable. However, notice the SKU here is a dummy SKU. So we're going to update that. Let's say stock, it's just going to be the only one we have in our system. And I'm going to update it to set the SKU equal to an actual SKU. So we'll grab that.

And I'm going to update it to set the SKU equal to an actual SKU. So we'll grab that. And we'll say Nintendo Switch SKU here. Next, the only other thing is it wants the full URL to where you can buy it. So that would be the product page. And you remember in Safari, I have that here. And update it. URL is this. Okay, so we have our product with stock at Best Buy. Next, if I use the Best Buy client to track that stock.

Using Tap for Updates5:49

Okay, so we have our product with stock at BestBuy. Next, if I use the BestBuy client to track that stock. Well, let's just instantiate it. And then check the availability for that stock. So let's grab it. Once again, this is where tap becomes really useful. So we can use, Laravel calls it higher order tap. It sounds kind of fancy. But sometimes you want to grab, for example, stock in this case. But it calls update.

But sometimes you want to grab, for example, stock in this case. But it calls update. And update doesn't return the stock instance anymore. For example, if I were to say stock, and then dd(stock). If we comment that out and give this a run. Whoops, I'm sorry, I have to import that. But yeah, if we give it a run, yeah, it returns a Boolean, indicating whether or not the stock was updated. So if I want the Stock model, yeah, sometimes what you do, just as an aside, is you'll say, okay, we'll store it in a temporary variable.

So if I want the Stock model, yeah, sometimes what you do, just as an aside, is you'll say, okay, we'll store it in a temporary variable. And then you can say stock update, and then you can die and dump it. And now we have our stock instance. So tap, if you want, just allows you to get rid of that extra step. I can bring it back and just say tap. What I actually want to return to this variable is what's contained within tap. But then if I want to call a method on top of that instance, I can do it. Just a convenience if you like it. So now if I run it, I still have stock.

Just a convenience if you like it. So now if I run it, I still have stock. Okay. Given I have a Product with stock at Best Buy, if I use the Best Buy client to track that stock, this should return to me stock status instance. So let's just dd the stock status for now. And then we'll talk about that a bit more. Okay, so you can see it's still trying to make that HTTP request to foo.test. And we don't want that anymore.

Okay, so you can see it's still trying to make that HTTP request to foo.test. And we don't want that anymore. So let's go ahead and get started. We now know the actual URL is this. So we're going to grab that, save it here, and then make a request to the URL. Next, though, we need to swap out the key. So let's switch this to double quotes. And then this should now become the SKU. And then this will be our API key. So we need these values.

Building Endpoint from Config7:58

And then this will be our API key. So we need these values. So it sounds to me, maybe this should be a method. Why don't we extract a method called endpoint. The endpoint will accept the SKU, but maybe not the API key. Maybe we can fetch that from the config. So API key, for example, could be config('services.clients.bestbuy.apikey'). Maybe that's what we will call it. And then we will return that URL.

Maybe that's what we will call it. And then we will return that URL. So this method is responsible for returning a URL to the proper endpoint for BestBuy. So now let's get rid of that. And we'll say make a GET request to the appropriate endpoint. And we'll say stock, that's our Eloquent instance, and grab that SKU. And so just to make sure we're on the same page, remember, we set the SKU here. And then give me the JSON results. Now we know this should be, what was it? online, online availability, and then salePrice is what we want.

Now we know this should be, what was it? online, online availability, and then sale price is what we want. All right, and I'll let you have a look at that. So if we give this a run, I think it's still going to fail. Yeah, undefined index online availability. So let's have a look at what's happening. This will be related to the API key. Yeah, so we get a 403, which means they can't validate our API key. And that's because of this section right here. So we're going to go into our config file.

And that's because of this section right here. So we're going to go into our config file. Laravel offers kind of a services.php configuration file that you can use as needed. We're going to do clients. What else do we got here? clients, BestBuy.APIKey. All right, BestBuy. And then it looks like Laravel uses key. So let's be a little more consistent.

And then it looks like Laravel uses key. So let's be a little more consistent. And we'll call it key. And that will return from the .env file, what did we call it? BestBuy API key. So once again, let's be consistent and just do BestBuy key. All right, so now we can easily fetch that value. If I come back to BestBuy, if I die and dump the API key, give it a run. We have fetched it now. So one last thing, let's rename this to key.

We have fetched it now. So one last thing, let's rename this to key. And there we go. So let's give it another run. But I'm going to intercept this. And there we go. We've actually made a real request. Run it again. And there we go. We have our stock status.

This is often a decent way to go and to store price. So this is yet another reason why we want to extract each of these clients into their own classes. Because they can then handle whatever translation they need to prepare it. So for example, maybe some random retailer, Target or something, they probably don't. But maybe they return the price in cents. In that case, you don't need to convert it to cents. But with BestBuy, you do. So those are all things we need to normalize. So in our case, if the price is $299, all you have to do to convert it to cents is multiply

So that'll use floor or ceil based on the current value. And this is what we want. $299 is $299. That's what you want. OK, but now in terms of our assertions, I can't assert that $available is false and $price is $299. Because again, we're making real requests. So what if you run the test six months from now, and they've dropped the price to $279? The test is then going to fail. So we can't rely on what they're responding with.

The test is then going to fail. So we can't rely on what they're responding with. Instead, let's see what we could do. We could just assert against the value type. And actually on that note, stockStatus. Why don't we just say, we could just say, well, this needs to be a boolean, and this should be an integer. So it's almost like pre-tests in this example. Because you might write a test to say, well, let's make sure it passes by checking if available is in fact a boolean, and if price is in fact an integer.

Because you might write a test to say, well, let's make sure available is in fact a Boolean, and if price is in fact an integer. But if we add these types, it has to be. And if it isn't, we'll see an error. So back in our BestBuyTest, we could do things where we assert that what we have locally doesn't match what's returned. Or sometimes what I'll do is just wrap it within a try catch. So just try to run this code, catch any exception, and we'll catch it at the highest level. And then here, we can fail. Failed to track the BestBuy API properly.

I wish there was just a pass method, and I don't think they offer that. I don't think they think it's a great practice. But in situations like this, I almost mostly want to ensure that when I run this code, it doesn't fail. So let's give that a run, and it does pass. But yeah, if for whatever reason, for example, we change this out, run it again, the test fails. And this is what I'm trying to track here, that the code doesn't break. Bring it back, run the test again, and now we have our first working Best Buy client. So the last little thing here.

Organizing and Grouping Tests14:08

Bring it back, run the test again, and now we have our first working Best Buy client. So the last little thing here. Now, this is looking pretty good, but a couple of things I want to address. First, if I use phpStorm to run these tests, it'll hit five tests, which is every test here. However, if I do it manually, notice it only runs four tests, and that's because we have this clients directory. So I could drag that into feature or unit. Or because it's kind of its own thing, let's register a new test suite in our phpunit.xml file for clients.

Or because it's kind of its own thing, let's register a new test suite in our phpunit.xml file for clients. And now if I run it again, it should include that. And now it's up to five tests as well. Okay, but the next thing is, I want to run my test suite as often as I want. And I hate the idea that it's going to hit the Best Buy API every single time. I don't need to run those all the time. Sporadically or on deployment is good enough for me. So what we can do in these cases is mark the classes with a special group. So we could say group API.

So what we can do in these cases is mark the classes with a special group. So we could say group API. Now what I can do is say, run my test suite, but I don't care about API tests right now. So now we're back to running only four tests, and it's much quicker, especially if we have a number of tests making API calls. So once again, without it, you know, still really fast, but this is a demo project. In real life, it would be maybe seconds. So 400 milliseconds there. But if we exclude the group, it's 100. So it's significantly faster if we exclude that.

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