Unit testing in JavaScript Part 5 - Mocking continued

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Good Monday morning Today we are continuing our series of unit testing you can check out the full episode playlist by clicking there And today we are continuing with Exploring mocking I am mpj and you are watching fun fun function All right, so let's have a look at where we were last time let me close this window this is the order total function that we were working on and we see here that we have we started a bit with calling fetch here and Well, it's not doing much We also needed to start doing some Response parsing here, so I think that that's what we were going to continue with I'm also going to open up the sandbox so that we remember what we're doing here So this is the way you do a fetch call You you call fetch with an url, and then you... uh parse the response in this case. We're parse it as JSON and then we're going to extract the the vat rate here, okay, so we have our fake fetch here and what we want this to do is return the Promise that resolves to response so you see here fetch Returns a promise and that promise resolves to this response object Which in turn has a json, Json method on it, that in turn will that will actually also return a promise that will resolve to this data here, so you know let's just do that actually so, fake fetch will return I promise that resolves to response object. This is a response object and that has JSON method That in turn resolves to futher it. It's a promise returns a promise that resolves to Oh, sorry I've switched to sandbox, and I resolve to this thing's it's data rate standard value. Let me copy that so that to just help me here. Resolves to an object that has rates Which in turn has a standard rate Which in turn has a value which is going to be a 19, perhaps. I made a mistake here promise dot promise. I'm drunk. Let me fix that promise or resolve is of course What am I meant anyway, given this then We should actually expect this to multiply the value of this order by 19%. Let's update the test to do that so expect result To be 20 times 2 times 1 19 Let's run that. Create integrated terminal, and run npm test, see what we get we should get a I expected to get a failure, but we didn't hmm that's peculiar Nooo, actually, it is not because there, I'm Hmm. Let me close that I'm gonna show you that mistake I made going to slightly zoom out as well so that we can see more So the way jest works is that when it comes to a synchronous test It needs to know when the test has ended so you know you can do that by Having these done functions, and then call them when at when the test is done We could see if that worked actually npm test Yeah That That works, but that's not the way we want to do it because it can also instead of using this callback pattern We can just return this promise here It's a bit more. you know, Promises are nice. It's a nice API. It's better than the done, done thing So jest will Cool so these will throw a throw an error and that will propagate up the promise chain, which jest will then handle. It's really sleek But either way we have a problem here. We expected the value to be something like this, but we actually received 40 Because we have no code for this So let's see here the fetch let's implement this Will return a promise that resolves to a response and response has a method called json that we can call which in turn returns a promise that resolves to... add some data and that data will have some rates And one rate that is the standard rate, and that with a value of 19, so let's go back can implement that data dot Rates and this is standard rate, and it has a value there and then We will use that that vat rate and will actually copy this copy this for now and multiply that with one hang on so the Take that times Let's just do that for a minute, we'll fix... that won't work, but we'll fix it later Let's just make some progress See what that turned out to be cannot read property, then or undefined. Where was that? orderTotal line three oh We didn't get oh, this is the happy path We have a bunch of tests failing now Let's actually disable all other tests and focus on one at the moment because It's very nice in programming to solve one problem at a time So adding it only to the jest means that it will only run this test which is often very helpful So let's see right now this fails Hmm all right it's still just returning 40 Yeah, it's because we We're not actually returning this this promise here It just makes this request and then it proceeds to this line here, which is not very useful so we press , write... return returrrrrrr....nn Cool let's run it again and see that helps. Oh, yeah Expected 47.59, but we received.. aaahh, 760. hmm. That's a bit much. It's because we are multiplying by 19 when, We should actually be correcting this to be 0.19 so I think that if we divide this by a hundred I think that's correct is that correct yeah, maybe let's see run NPM test again No that becomes 7.6. Now that's because we are not multiplying by zero point 19, so it's actually the 1 plus Zero point 19 see if that helps hang on ah Yes, cool. Now. We were to green get the correct value. I keep typing NPM test here, but I just Remember that we actually have defined an NPM watch as well So sorry npm run watch that will auto run every time we Every time we save all right, so There's some duplication here. Don't worry. We will deal with that eventually but for now you mmm... put a pin in it we will be removing duplication, but not until all tests are green So let's actually Let me remove it only, to see the other failed tests, they are not failing because then is undefined yeah and this is because in the cases We only really do this we only really want to do this if We have a country and The order might not necessarily have a country at perhaps the user haven't selected it yet sooooo... we want to just have an if statement here and do order.country And just wrap this thing in that hang on ...aagghh There we go And now all those tests are are succeeding We have one skipped test here because I actually made Kind of dummy test here. This is goal like I'm I think of these as to do to do tests so to speak Because I wanted to remember This case but it seems like we have actually accidentally Solved this because we had tests breaking for other reasons So I'm actually gonna delete that we don't need to write that test that is overzealous Now that we have other tests that Just cover that naturally Also, I think that this empty function here We don't actually need need that anymore because it's just not making use of it So I can just change the empty function to null to be honest Let's do that So let's see Null orderTotal, null... Then the empty function null and null there as well we don't need that, i just delete it. This is a bit cleaner. I feel a little bit disoriented here with all this mocking It feels like I don't quite know What is real? I'm skeptical are we just? Whatever. We are we actually testing anything here, or are we just creating this fake fake implementation and then Just testing the fake implementation are we actually testing any real logic? Yes, we are like I understand how it might feel like we're doing quite a bit of faking here doing this elaborate mock or fetch, but what we are concerned about is to check to test if order total is Causing the side effect that we want the fetch and that it Does the right things with What that would that side effect the yields which is which is the data so what the test is doing is we're concerned with testing order total, right? and What or the total does is they cause as a side effect fetch. So this side effect comes out of order total so to speak And we were inspecting that this looks correct That's what we're doing and then we are passing a response back into order total And then we are inspect what comes out of order total after that to see that that is correct so like request comes out we inspected that request mmm looks good looks like we expect it to be then we pass in a Response and then given that response we inspect that hey we get to correct VAT out of that or like the correct Order total where VAT multiplied in so order total is what we're testing We're not actually we're not testing fetch at all here. I'm skeptical Does this actually work? Is is this, we've written a lot of tests now we didn't want a code But we have not actually tried it Against the real API we built it checked it out in the sandbox kind of but we've not actually check that order total runs correctly against the real API. I'm interested in the fact that When you're doing TDD with mocks it can only become kind of sorta TDD Before we were coding like TDD with pure functions We were writing a bit, and then we implemented it in the code And we would actually see the real results because there were no side effect. It was just the pure function and our tests But when we are doing TDD Against mocks, it's just us creating a fake reality and then we check using TDD that our our tests does the right things in this fake reality and Depending on what happens in the fake reality that...the test does Response to that sorry the code responds to that in the right way But it all depends on us having the having correctly designed the fake reality. which means that when we are doing any kind of mocking we actually do have to actually test that we have made right assumptions in our test by checking the stuff in the sandbox so Let's see if we can do that actually I'm going to do import the order total... order total and we require And I'm gonna close this for a bit. I'm gonna start quokka on this file There we go and We're gonna call order Const result We've got a call order total and the first argument and pass in a fetch because it needs fetch and We are going to give it some kind of Order let's steal one from this This test here go back to sandbox Pass in this here see what happens oh? Cannot read properly standard or undefined Interesting what is happening? So rates is undefined. That's actually just been x console.log x see what happens 401 Authentication required, please pass a valid API key had it in your request ah yeah That's because we need to actually give needs credentials here So we still have some work to do in our test Let me close this for a while and have a look so not paste this in gonna just grabbed this here to help us have it side by side Go back to the test you're gonna paste this in here while we work if you you if you have a big screen Unlike me who I was doing a youtube channel You can just split your editor side-by-side. That's very handy when doing unit testing to keep the tests here at your reference code here But either way This Is going to be passed here as an option, options object, when I call it opts at least and we expect headers Dot no sorry respect opts headers And we expect that you have an API key Property we expect that to be Expect that to be key one two three, so what is key one two three? well Here's the thing we also because this uses process here, we now have another dependency and We need to create a fake process as well and pass that in, so Functions tend to have a multiple dependencies and that has an 'env' Which in turn has a VAT API key which in turn has Should be key123, so let's actually Pull up the terminal in toggle terminal and hang on run all tests cannot read property headers of undefined. Yeah, because first of all It's not getting an opts Let's remove this Let's actually fix that first so order total will now pass in some options here, See what happens can not read property API key of undefined yeah sure because it wants a headers Bonk! we get a new problem here. Yeah key123 received undefined Let's actually just API key, and then I'm gonna write the hard code the key here so it's key123 start faking it But we want with we can't hard code values like this, so we're going to proceed. well, Hmm actually gonna passing process here This is the process object we inject that Now this will break all other tests So let's actually disable everything, but this now I'm back and Dudududu Cannot read property country of... of undefined, hang on! what is confusing me here Yeah, we actually have to pass in the fake process, otherwise the arguments order is incorrect fake process. cool , calls VAT API correctly. It's green, but it that's because we have a fake value here I'm gonna use the actual value from process process.env What was it again? hang on, going back to the test It's VAT API key oops And it is green! cool. Let's just change this just make sure that it breaks correctly yep awesome we're gonna remove it only and then we're gonna see that all the other tests fail so that's because they don't have a process object These because these don't use the don't use the fetch, We can just pass null in here as well. They don't matter don't make use of this These test cases so just gonna do null, null and we have five passed So now it now, It actually uses the The correct way, VAT API key, so let's try Try this again try this again Cannot read property country of undefined no oh! okay of course we need to pass in the process in the sandbox as well All right! cool. Yeah. We cannot read property standard of undefined. Let's see what is happening here. Let's check this again x... What's happening console.log(x) see oh my god Bad requests, what's bad about it? So it was because I had run out of credits. I refreshed them again Ha note to self don't use a throttle API for tutorials cool So let me remove this console log And go back to the sandbox Finally it works awesome All right cool, so we wrote some tasks that completed the whole Response chain and the parsing of the response, and then we also Verified that the our mocks our assumptions about the fake reality that we created actually correspond to reality by Running our code in the sandbox and pow. It seems like it's working that calls for celebration And by celebration, I mean a commit, oh there is changes in the package dot json? Yeah, oh, I just indented some code. Let's Keep that separate. The sandbox also got some changes. Let's actually Let's say git commit that as well And Script.md, We don't want that, that's my script notes, and I want to remove the the package of JSON there because it was just That was just indentation and we want to keep those in a separate commit. I don't like putting You know spelling fixes and stuff like that baking them into a commit. I want I kind of want to do them separately we Fixed response, Test Yes commit messages are Important but not that important. Well, they are I think they're really important, but this is not a tutorial about good commit messages any how Let's still do this derailment Fixed indentation issue I know I'm being Inconsistent but Let's see, let's see, let's see, so this is what we added here some nice New response parsing we have some duplication here that we will eventually eventually fix, we looked at the we created extended our fake fetch here by Checking that it Used the API key, that is also passed through fake process, and it's also we also checked that it use the rate here from the ...from the fake VAT API to calculate the output result This thing here, this is actually now redundant because you know since we're checking the output Which is completely dependent on... Fake fetch actually being called, otherwise it wouldn't work, This thing is just completely superfluous, so we're gonna remove that. No longer needed. Now and we can also remove these curly brackets we don't need them anymore. Let's actually just make sure that the tests are still running dunk 5 passed, so let's let me commit that Removed Superfluous checks.!!! I feel like this injection here results in extra code if you were not unit testing this and Requiring this thing here it would Like that would mean that order total could just have required this on its own inside of itself it feels like an injection mechanism adds a little bit of extra code and Extra code, but it makes me feel yes, it's a little bit extra code, but... It's it's not a lot. It's it's pretty nice. It's pretty clear. What is happening here. We just Requiring in fetch, we're passing it in... It's very easy to follow how the injection happens, process is here a I mean There are other ways we could achieve it. We could use some kind of... ...messing around with globals, and stuff like that, but it wouldn't really be easier to follow It might save us a little bit of code, but it would still It feels like it would be more brittle. I like this because it's extremely straightforward What is happening. Jest does have an ability to override requires so if we used fetch inside like it with the require inside of order total We could use that, but We would still have the problem with with process, which is a global variable so we would have to like mess around with that global. One advantage with this is that it makes all dependencies All dependency mocking behave, in same way, which I think is pretty nice And I think that's a good point to end this episode. It's getting kinda long If you have any questions confusions or wanderings or suggestions on where we should go next Just post a question down below in the comment field or if you are a patron you can post it in the fun fun forum There's a link in the episode description for a topic Dedicated to discussing just this episode you have just watched an episode of fun fun function. I release these every Monday morning 08:00 GMT if you are watching from the future you can check out next week's episode here And if you're watching from the present you can click here to subscribe so that you don't miss that episode You can also turn on notifications in the YouTube app if you're forgetful. I am mpj until next Monday morning stay curious!
Info
Channel: Fun Fun Function
Views: 26,910
Rating: undefined out of 5
Keywords: programming, coding, javascript, computer science, software engineering, software, functional programming
Id: ZbModC5pqv0
Channel Id: undefined
Length: 29min 44sec (1784 seconds)
Published: Mon Dec 11 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.