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

Creating Feature Test0:00

Alright, so have a look. We're getting our bearings here. We're figuring out what messages our models will send to each other. But yeah, we don't really have a feature test yet. A feature test is from the outside in, almost like the way a user will interact with your application. So in this case, we're not building a web app, we're building a console application, which means our entry point will likely be through an artisan command. With that in mind, I'm going to make a new test here. I'm assuming the command will be called track, php artisan track. So let's call it TrackCommandTest. Alright, and yeah, let's get started. So it tracks product stock. I mean, that's basically what this does. And we will optimize. So I'm going to split this into given, when, and then. For example, given I have a Product with stock, when I trigger the php artisan track command, then what should happen? Well,

going to split this into given, when, and then. For example, given I have a Product with stock, when I trigger the php artisan track command, then what should happen? Well, then the stock details should be refreshed. Right, so let's remember what we're doing here. We have a Product with stock. A Switch is available at Best Buy and Walmart and Amazon. When you run this command, we're basically going to, however we can accomplish it, we will ping the web pages or the APIs for those respective retailers. So we'll hit Best Buy's retailer, and we're going to check, is the Switch in stock? If so, what is the price? Is it on sale? Is there anything else we need to know about? Once we have that information from their API, we will update the stock record in our own database, and then provide it to the user. Okay, I think we're ready to go. So given I have a Product with stock, well, we've already done this here, right?

the stock record in our own database, and then provide it to the user. Okay, I think we're ready to go. So given I have a product with stock, well, we've already done this here, right? And it's basically the same thing. So I'll tell you my rule. My personal rule is I allow one copy, but when I do it, I have to make a mental note. Hey, you just copied this. Next time, you need to figure out a better way because you don't want this duplication everywhere. So it's sort of like a warning. It's a yellow light to my future self that you can't do it again. The next time, you need to go ahead and move this to either a method or a factory class or a special database Seeder class, which is what I will probably do. Okay, so given we have a product with stock, done. Next, when I trigger the php artisan track command, we can do that by saying artisan track. Then the stock details should be refreshed. Okay, so now think about it.

product with stock, done. Next, when I trigger the php artisan track command, we can do that by saying this artisan track. Then the stock details should be refreshed. Okay, so now think about it. How would we confirm this? Because for our test here, at least at this point, I don't actually want to hit a real API. We're not to that point yet. That'll be towards the end. So for now, we're going to fake the API. And instead, let's say when I trigger the php artisan track command, and assuming the stock is available now, then we should be able to say stock, get a fresh copy from the database. And if I look at the inStock field attribute, that should now become true. And usually what I do is I add a before and after, just to make it crystal clear what I'm checking, especially for somebody else or myself six months from now, I can see, all right, well, this thing was false. And then I did that thing. And this thing became true again.

Fixing Boolean Casting3:23

what I'm checking, especially for somebody else or myself six months from now, I can see, all right, well, this thing was false. And then I did that thing. And this thing became true again. It makes it a little clear for me. Okay, so I think we have enough here to get started. I'll give it a run failed asserting that zero is false. That's kind of a confusing one, isn't it? However, I'm pretty sure it's related to this. So if we were to comment those out and run it again, we get the same thing. So think about it in stock in our database is stored as a 1 or a 0. But in our case, we're actually checking for false. So of course, I could cast it myself. Or we might want to go to our Stock model and be explicit here. Let's cast the endStock attribute to a Boolean. And now we'll never run into that issue. Alright, I give it a run. And now we do get green. Let's bring this back. And it should give us our next step. Yeah, no artisan commands.

Generating Track Command4:12

to a Boolean. And now we'll never run into that issue. Alright, I give it a run. And now we do get green. Let's bring this back. And it should give us our next step. Yeah, no artisan commands called track. Alright, php artisan, make me a command called TrackCommand. So that'll be stored in your app/Console/Commands directory. Our signature. Yeah, you might want to namespace this if this were a larger application, you might do the application name and then something like that. But I think we may just have one, maybe two commands here total. track all product stock. Okay, we give it another run that will auto register itself with the framework, which means we've now changed the error failed asserting that false is true. Of course, because we ran the command and that didn't do anything at all. Okay, so let's figure out, we run this command, and it sounds like we need to check our products, find the stock

Tracking Products and Stock5:00

Of course, because we ran the command and that didn't do anything at all. Okay, so let's figure out, we run this command, and it sounds like we need to check our products, find the stock associated with that product, hit an API endpoint to basically refresh the current state of that stock, and then update our own database based upon what is returned from that request. Right. So let's see. We don't need that. Maybe we're going to do this for all products. So get all the products from the database. Remember, in our case, I can't imagine we're going to have more than even in real life more than about 100. So I'm not worried about doing a product all. But yeah, clearly, if you're doing 20,000 products, you would need to you need to reach for something else, maybe chunking, or each, we'll do that for you as well. Anyways, we could say give me all the products. And then for each one, I want to track it, you know, we keep using that term.

else, maybe chunking, or product each, we'll do that for you as well. Anyways, we could say give me all the products. And then for each one, I want to track it, you know, we keep using that term track. So let's make sure we work it into the code for each product track it. Okay, so now, of course, we run it, there is no method track on product. So we'll go there now. Let's do it up here, track, run it again, we change the air, because once again, we're not doing anything here. So how do we track this product? Well, we know for the product, there's any number of stock associated with it. So maybe I could say get all the stock and for each one. And remember, stock might be for the Nintendo Switch, it might be a Best Buy, there might be one at Walmart, there might be one at Amazon, that's what we're calling stock here. So for each of those locations, let's just call track again, let's do the same, the same exact thing here.

Retailer-Specific Tracking Strategies9:08

detect it as best as they can and block you from doing that. All right, something to think about. So anyways, how do we know if we're making an HTTP request or screen scraping or something like that? Well, that's where the Retailer comes into play. We know that Stock belongs to a Retailer, right? We haven't set up that relationship. So any Stock belongs to a Retailer. Now I could say, if the Retailer's name is Best Buy, then here's what we need to do to satisfy a Best Buy request. If it's Amazon, maybe we try to screen scrape. If it's GameStop, maybe we fire up a browser to actually hit the endpoint. So think of these as different strategies for getting the data we need. So you'll notice I'm doing it inline here. But as you can imagine, for each different strategy, very quickly, you end up with something like this. And of course, each of those conditionals will have many, many lines. So clearly, we don't want to stick with this. But we're not quite ready to

Faking HTTP API Responses10:05

very quickly, you end up with something like this. And of course, each of those conditionals will have many, many lines. So clearly, we don't want to stick with this. But we're not quite ready to refactor from this. So just keep that in mind for now. We will be changing this later. Okay, so here's what we're going to do. I'm going to die and dump the results because I want you to see this. So we run it. And yeah, could not resolve food test. So it's actually trying to hit that endpoint. But I don't want it to. In fact, I'm not ready to test this, this portion at all. So what I can do is come back to our test. And I can say, well, we're going to fake that HTTP endpoint, or in fact, any HTTP endpoints. So now if I run it again, you'll see we run right past that. And at this point results, just to refresh your memory, what was returned there, the JSON results is null, because we didn't do anything. But what's cool is we can fake it.

run right past that. And at this point results, just to refresh your memory, what was returned there, the JSON results is null, because we didn't do anything. But what's cool is we can fake it. So I could say, well, for any endpoints, we're just going to return foo bar. So this is going to be the faked version of the response from the API. So we give it a run and it does return foo bar. So yeah, again, this is where you want to be a little careful. Because you never want to be in a situation where you don't actually test against the real API. Because what if they change? What if they update? And what was called a sale key is now a sale price key, right? Well, you can end up in a situation where the tests are passing. But in production, it fails because you're not actually hitting their API. So this is why you want to have some tests where you use fake data. And then at least a few tests that work against the actual third party API. So in our case, we're going to

hitting their API. So this is why you want to have some tests where you use fake data. And then at least a few tests that work against the actual third party API. So in our case, we're going to say, imagine it were the the API returns a key as part of its results called available. And we'll say true, maybe it returns a key called price. And we'll just set that like so. And again, maybe there's other things we'll want to grab in the future. But for now, let's say it returns that Well, if it is available, we should detect that and then update our stock in our local database. Alright, so have a look, we run it. And now our fake API request is returning this. Alright, so let's come back to stock. So we could say, well, we're going to update this existing stock. And I will check or I'm sorry, I will set if it's in stock equal to results.available. And then we'll update the price as well. But again, we want to be careful that we we massage

stock. And I will check or I'm sorry, I will set if it's in stock equal to results available. And then we'll update the price as well. But again, we want to be careful that we massage this return data, however, we need to. And we'll talk about that more in a little bit. One API might return the price in dollars, another API might return it in cents, one API may have a key for the in stock attribute, it might be available. Another API will be isInStock or stockAvailable, right? So you need some way to normalize the results of these requests for all the retailers, so that we can easily update the stock in one place. And I'll show you how to do that soon. Alright, so let's give it a run. And it passes. Kind of cool. So notice, here we go, hit an API endpoint for the associated retailer, fetch up to date details, and then refresh the current stock record, we took care of it.

So notice, here we go, hit an API endpoint for the associated retailer, fetch up to date details, and then refresh the current stock record, we took care of it. But again, I just want to drill this in, if we were to deploy this, the code wouldn't work. So this is a situation where the test pass, but the production code fails. It's very important. So in the future, once we start working on the actual APIs, we will have a BestBuy transport test or something like that, that will actually hit the Best Buy API and confirm the data and the type of data that is returned. Okay, so if we switch back to our command, here we go. So now we've added the ability to run php artisan track. And when we do, we will fetch all available products. And for each one, we will track it. We do that by grabbing the stock associated with each product and tracking it. stock will figure out what retailer it's

class that corresponds to it? And what would we name that class? And what would go in that class? So these are all things to think about. I'll see you in the next episode.

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