Identifying Price Bug0:00
Now, before we move on to manually reviewing our application, there's one lingering bug I need to fix. Have a look here. When we check availability, that will return the current stock status, and if I give it a run, you'll see the price is set to $29,900, right? However, if we go to the implementation, and if I dump the results from the API call, you'll see the sale price is actually $299.99. We're losing a dollar, right? So we're saving this to our database, but it should actually be this. We have an issue here.
Writing a Regression Test0:37
So we're saving this to our database, but it should actually be this. We have an issue here. So I'm going to solve this by writing a regression test, and it's kind of a loose term, to describe a test that reproduces a bug in the system. So we write a test to confirm that something's wrong, then we fix the bug, and then we rerun the test to verify that it's no longer an issue. Okay, so let's do that now. We'll say right down here, it creates the proper stock status response, or something like that. So yeah, let's see.
like that. So yeah, let's see. How do we want to do this? First, let's bring this back to what we had before. Yeah, I kind of want to say, well, if I call the checkAvailability method, and I don't want to hit Best Buy's API, so we'll fake it. And then when we load up the stock status, let's make sure that the properties were assigned correctly. Okay, so let's say HTTP, we're going to fake, and I'm just going to return our hard-coded response where the sale price is going to be $299.99.
Okay, so let's say HTTP, we're going to fake, and I'm just going to return our hard-coded response where the sale price is going to be 299.99. And what's the other one? Online availability. That will be set to true. Okay, next, if I new up our BestBuy instance, and I check availability for some stock, now in our case, I think I can just get away with instantiating a blank Stock instance, because we're not going to use it. But if you need to, of course, you could reach for factory make or factory create. But yeah, let's just see if I can get away with that.
But if you need to, of course, you could reach for factoryMake or factoryCreate. But yeah, let's just see if I can get away with that. Now, if we run that code, it's going to return a stock status, and then I could say assertEquals. And yeah, right now, that price is being set to this. But we really want it to be this. So let's say stockStatus price, and then we'll do one more for the availability. So that would be true. All right. So with any luck, we should have reproduced the bug.
Fixing Cents Conversion3:06
we convert dollars to cents. But you'll notice in the last episode, I did that very quickly, and I forgot to properly wrap this within parentheses. Because think about it. What I did is we convert the sale price to an integer, and then we multiply that by 100. So for example, if we put up php artisan tinker, and I convert 299.99 to an integer, we get 299. And if we then multiply that by 100, you can see the error there. So of course, what we should do instead is wrap this within parentheses. Now we're saying the result of this expression should then be cast to an integer. And if I run it again, great.
Refactoring to Helper Method3:42
Now we're saying the result of this expression should then be cast to an integer. And if I run it again, great. So now the only remaining thing we might consider, I think it's fine, it's very simple. But if you come back to this, it might take you a moment to figure out, okay, why are we multiplying by 100 and then converting to an integer? You'll figure it out, but it might take you 5 seconds or 10 seconds or so. So instead, what if you said, well, let's just convert dollars to cents, and did something like that instead. Now, of course, I run and it's going to fail, because that method doesn't exist. But we could add the method, and then reproduce what we had before.
Now, of course, I run and it's going to fail, because that method doesn't exist. But we could add the method, and then reproduce what we had before. So that would be salePrice times 100. So rerun the code. We still get green, but yeah, now, when you return to this code a year from now, it won't take you 2 seconds to realize what's going on here. Oh, we're converting dollars to cents. Now you might consider, if it makes sense, storing functionality like this directly on stockStatus, sort of like a setter. But I'm not sure it's going to be needed elsewhere.
Improving Test Failure Messages4:46
stock status, sort of like a setter. But I'm not sure it's going to be needed elsewhere. So until I reach that point, I'm fine keeping it as a helper method here. Okay, so now if we return to our BestBuyTest, everything's passing, so I'm about to let you go. But just one last thing, if you don't mind. This first test, it tracks a Product, and it returns green, which is great. However, imagine, maybe for whatever reason, a attribute gets changed. So I'm going to fake that by saying, unset results, salePrice. Let's just say they remove that, the API version doesn't get updated properly, or just things
So I'm going to fake that by saying, unset $results, $salePrice. Let's just say they remove that, the API version doesn't get updated properly, or just things like this happen. So now we're trying to instantiate stockStatus using a response attribute that doesn't exist. Now if I run the code, it does correctly fail, and that's a signal to us something went wrong. But notice how I have no feedback about the next step. What do I do to solve this bug? I don't know. I'm just going to have to go through it line by line. Let's fix that by returning to our test.
I'm just going to have to go through it line by line. Let's fix that by returning to our test. We're doing it in a try-catch, which is fine. But notice we catch the exception, and then we don't do anything with it. So with that in mind, why don't we append the message of the exception to the failure? Now notice if I run it again, failed to track the Best Buy API, undefined index, salePrice. With that small tweak, I instantly know what the problem is and how to fix it. Okay, let's bring that back, and in the next episode, we'll review the application.