EMBERCONF 2015 – TEST-DRIVEN DEVELOPMENT BY EXAMPLE

Just another WordPress site

EMBERCONF 2015 – TEST-DRIVEN DEVELOPMENT BY EXAMPLE

alright so if you’re here Devon test-driven development by example when I put this talk together I was sort of thinking I couldn’t do a talk if it wasn’t a big announcement like HTML bars or something that would blow away Tom and you hooda and then I thought well maybe maybe there’s other people at the conference who aren’t working on the next rendering engine or something and maybe they’re just wanting to build web apps like I do so hopefully this is this is for you all right before we get started though I want to show the app that we’re gonna build in the next 30 minutes and it’s a really simple conv Ford it has some items on the left that are unassigned and then I can click this little blue item and it will assign those to the assigned item on the right and then I can drill in by clicking the name of any of these it’ll kind of show a details section and those details are data bound and the intent really is to just show how to get feedback with test-driven development when I first started learning test-driven development it was more about finding something that would prescribe success and ultimately TDD was not about that so I kind of learned incorrectly how to do it learned correctly and then still sometimes learn incorrectly how to do it I hope today just to pass along some of the information some pro tips maybe all of it’s not that grand but you’ll pick up one small thing and a lot of times when I was younger I was felt like when I came to these it was the really small thing that I saw during a coding demo that was more interesting sometimes than the whole presentation or where the presentation was centered so to get started we’re using an ember CLI app of course just to make this a whole lot easier and we’re gonna start out just by generating an acceptance test to get started and I’ll call it assignment and usually I kind of start when I’m doing just line of business stuff I’ll kind of start with a high-level test just to feel like I know where the client or the user the end user is coming from and in this particular example we just have unassigned and assigned items the simplest starting point really is do we have items that are unassigned or they grouped together and do we have assigned items that are grouped together so we’ll start out with the unassigned column we’ll basically find a table of unassigned and it’s ER I have this little TR I call it cards I don’t know sometimes they Kanban boards you call those cards and then also we’re just going to assert right now that there is a certain number of these in the Dom to kind of get us started so we’ll say the length of this is three and one thing a little pro tip I want to throw out if you’re ever doing any live coding you might see it in the upper right corner is the best way of success here for live coding is turn off Wi-Fi don’t attempt to npm install anything you’ll just instantly troll yourself guaranteed something’s gonna break so I’m not gonna npm install anything up here today all right I am however going to be flipping and I hope the monitors catch this I’m gonna be flipping between the live code and the test run and if you’re new to ember and you haven’t seen this you can actually do a test run by doing test – – server that will continually watch and then live update the test so I’m gonna start with our failing test at the very bottom there you can see we expected three of these unassigned items and one of my gripes what test them is that well what is what’s the other side well it’s technically undefined there is just no entry in the Dom for this so the first thing we’re gonna do is just jump into the router and actually define a route for these two do’s that I call them and we’re just going to work for simplicity in this demo at the root of the application and that gives us access now to work away from the application handlebars template so we’ll just create one called two do’s and we’ll have a really simple table or something looks really a simple table and I called this thing I give this a class of honest and then I for some reason decided cards it was a good name for the ETR and we’ll flip back one of the things I want to point out here is earlier in my journey for test-driven development I always thought red green refactor I had to go from red to green and that would make some changes but honestly what I’ve

found over the years is that I use the red over and over again to get feedback even if it doesn’t go directly from red to green so in this particular instance I’m showing that I’m on the right track because instead of three is undefined I’m now getting three is not one all right so we know the answer of this we’re just gonna do an each loop here and say each to do in some kind of computed here say unassigned and we’re gonna do that we’ve got to obviously add a controller real quick so we’ll add a to dues j/s here and we’re just basically to a very simple controller and we’ll create this unassigned property and for right now since I just need to pass it kind of the simplest amount of code to pass this is to return an array with at least three items in it and then we’ll use another test to kind of drive the requirements of what did these two Do’s actually look like so we have a passing build no applause please that was literally not worth it so old on I’ll have something better I swear so we’re gonna do now is we’re gonna go get just the first property which if you remember the final result we basically have like a project name so we’re just go get a project name from there and I’m gonna do that just by going to the zeroed item essentially in the cards list here and then I’ll find a TD with something like to do project in it and then I’ll say project text should be something like first we’re just gonna this is arbitrary data of course we’re just making this up and we’re getting of course a failing test which is great tells us where we need to start now if we looked at the handlebars side the first thing I like to do this cuz I’ve been burned by incorrect selectors so many times is I like to come in and just kind of put an incorrect value so I’m putting an X there anyway just to make sure that I’m in the right track oftentimes I found myself doing multiple steps only to find out I didn’t have the right CSS selector at all so this will help save you that painful moment hopefully so we know we have we have an ideally we’d actually like to do something like to do that project and this is the failing test that we sort of wanted that last time around where if we’re just returning a list of integers there’s no way we’re going to satisfy this so let’s just create some really simple sample data and we’ll kind of iterate on this controller so create a project with first and we’ll just throw on some first second third data here and second third and now of course we get a passing test because we have great data this of course if we’re looking at the controller it’s of course not the greatest controller yet but we’re gonna incrementally get there as we drive sort of the other side of this requirement but before we go write a test I want to come back and look at the handlebars because the first thing I noticed at the top of this is we have a table and of course they’re not trending on hacker news right now so our designer decides we’re gonna change this to divs or something like that and they come in here and from the behavioral perspective with this refactor there really shouldn’t be anything that changes from the test right so if I change TRS and tables and change this TD to a span the behavior of the web application is the same unfortunately the tests don’t reflect that I should have had a clean refactor here and I call this out because the tests I wrote on purpose were kind of like the early tests that I wrote when I was doing ember testing or selenium and they were very structural or layout dependent but in reality these tests are about behavior they don’t care if I have a designer this wants to change it all back to tables or divs so let’s just come in here and remove anything specific to the layout so I’m going to remove anything like TD and of course remove table and now we get a passing test so if we want to go to change them back to tables it’ll still pass it doesn’t actually matter and as a front-end engineer just trying to get the behavior of the web application I don’t actually care excellent so now we have sort of the happy path on the left side for unassigned but we obviously need to finish the story because the Kanban board is not necessarily only unassigned and also I noticed this terrible test named a pair programming with 600 people and nobody caught that oh come on now you’re fine okay so say assigned items are groups together and in this one in particular we’ll just basically replace unassigned with the signed and the only thing I’m really gonna call out here is that you definitely want to have a different number when you’re kind of just making up arbitrary things like I am and in this case I want to make sure that there’s only one assigned item when we

get started and then it’s kind of a different number from the unassigned just to make sure I don’t mix something up and I do still get a failure that one is not undefined so we know we know what needs to happen on the controller side because we need at least one item in here so we’ll create an assign computed and inside here we’re just going to really return again fictitious data until we get to a point we can refactor it further so we’ll say last is some project with different text again so we’ll save last and then on the on the handlebars side we need to basically copy this and eventually you can imagine this gets extracted out as a component of some kind all right so I’m just gonna make one change here which is to not completely get the implementation right because I don’t actually have a failing test there and so now we have that piece of it passing I’m not actually asserting this line yet we should actually get us a failing test right now so we’re gonna do is switch back to our test code here and bring back kind of the final failing test for the unassigned assigned story and that is if we go fetch a product from a sign that it should have the text of last which should fail us right now we have last is not X which makes sense so if we go back to the handlebars template here basically just stub in to do project now we have a passing test now we’re at the point where on the controller side we can actually do the refactor to get us a little bit closer to a real ember app if you’ve been do an ember you’re probably very disappointed in me right now like Turin this is not what we talked about but honestly we’re gonna get to the point where this is just a model property so let’s incrementally move there just by actually adding this and kind of extracting out and then we’re gonna have to come up with some kind of property that I assume the the back end either I has a back end developer where someone else on the back end has decided will be the status code indicator so in this case we’ll say we have something called status underscore code and this status code will be the thing that determines if it’s been assigned or unassigned on the back end so now we can do in here is actually just returned this dot mop or this Tucket model dot filter and inside here we’re just really gonna return if the models status and her score code is a 1 because in this case we just arbitrarily decided we’d do a 1 and then in his bottom case we’ll just do it too so well what’s that sorry about that don’t troll me we’ll get there we’ll get there yes somebody has actually already seen this talk they just didn’t want you guys to enjoy it sorry about that all right so I’m gonna rip the model out it’s obviously important it’s gonna break the world here so the reason I ripped that model property out is we’re gonna go down two routes and a day to do zjs just again getting us incrementally krause closer to the final version of this so I’ll do em birf remember and export out a route here and basically just paste this in verbatim right now we’re just trying to do the simplest thing to get us back to a passing build and now we have a passing build stellar and the next thing we’re gonna do is just write a failing test that we can actually get the status from this if you remember in the final app I actually have kind of being grey and then in in green here the actual status sort of in plain English and the challenge for us won’t as we write this feature is right now it’s just an enum or an integer value from the database so we’ll need to actually drive that out so we’ll say status is shown in plain English and that’s how I got my writing test name responsibilities revoked so we’ll do a slash here and it’s really going to be sort of the start of this same test here and the only difference is we’re going to ask for the status itself so first thing we’re going to do is write the failing test here so we’re gonna reach in to the assign the zeroed item because there only is one right now and ask for his status and of course this is gonna give us a failing test here says there’s nothing and the first step really is to define the CSS selector in the handlebar side so let’s come into the assign side here and I know this is gonna fail but I want a little bit more information so

I’m gonna put an X on the end just so you can see that it’s still undefined and now here’s the challenge with purely acceptance testing is acceptance testing is great to show the happy path flow from your route to your controller to your template maybe some model in there what it’s not necessarily the best that is some of this quicker feedback for conditionals and especially conditionals that have computed properties so what I’m gonna do now is actually break from purely acceptance testing this and on purpose I’m gonna leave us a failing test here but I’m gonna break us out of that test run and actually go add a unit test that’s just gonna drive the assigned transformation from status code to status so we’ll drop down to the test directory here and just do a to do model test j/s and i’ll say the little boilerplate here by half cheating will say status code one is unassigned and we’re still a subject here is to do that create adding a status code of one and let’s do assert equal subject dot get stennis and this of course is unassigned now if i want to run this test in isolation i have a module name at the top here just called to do one of the cool things if you didn’t know about ember CLI when you’re in this predicament that i’m in where i want to run just one test you know I haven’t I know I have another failing test that’s causing me some grief and when we were on this one in particular I can do a cool filter command here and you they filter down to just this particular module or test and I know I have an error here which says to do is not defined which is kind of like our first failing test so are actually gonna import to do from what will be in just a minute the Kanban models to do and we need to actually go add that to the models directory here let’s say it’s a DJ s and just export out a really simple model here and the only property we’re gonna actually have a course is status and right now I’m just gonna return X because we didn’t actually see a good failure so now I’m seeing we expect it on a sign we actually got X now really to make this first test pass I could just slam in signed I don’t really have any conditional Drive here so the next failing test will actually drive this out so we’ll just kind of add another test yet it says of course the other side is status of two will be assigned and this is kind of the test that gets us a little bit further to solving the acceptance failing acceptance test so we get unassigned is not assigned imagine that we hard-coded it so we’ll say status code is this tie get status code and then right now if the status code is a one we will return unassigned otherwise we return assigned and I should get us a passing build and it does all right so now the other reason that somebody called out computed earlier but another reason I like the unit test especially a conditional that’s being driven from a computed property is so many people seem to miss the cache breaking component of computed property so what better way then to write a failing test for it so what I’m gonna actually do is write that test that if we said subject set status code slam that into a two I should get a failing test now and all we need to do is that status code and then we’re back to essentially a really clean model its tested one of the other examples I want to point out here from this unit test is sometimes I write tests and I get very emotionally attached and the experience and all seriousness and this bottom test I’m very emotionally attached to it because I had the live code that’s in front of all you guys it’s kind of a big deal and so but I noticed on a couple a couple lines a couple lines up I’m actually testing that though right here and we have to be aware or cognizant of every test is just as expensive or just as big of a burden as the production code that it maintains or it helps us maintain so in this case I think it’s acceptable for me to break that out not anymore than really two conditions right here anyway so I’m gonna break that out and still feel good about myself all right and the next thing we need to do is I want to go back to non-filtered the non-filtered test run so I get back to my family test and that’s in part why I leave a failing test so I don’t forget about it and we can remember where we’re at now we had the acceptance test that supposedly had a status property but it doesn’t seem to

be hooked up for some reason so if we go look at the route that’s actually pushing down these objects you’ll notice they’re not the new to do model so there’s no way we’d actually have access to this status code so I’ll bring in the to do model here and actually do a to do create and now that I have all those created you’ll see I’m getting assigned X should have actually pulled that out of the handle bar side but now once I pull that out of the handle bar side we should have a green test run which is what we have so that’s kind of illustrate in that example really that unit and functional or acceptance test they actually live together in harmony it’s not it’s not one or the other so hopefully that example kind of showed that off all right so let’s drop down and write another test here and this one will just say clicking the assign button will move item from unassigned to assigned and this test will really drive the computed that’s lacking that it’ll basically expose a bug that we have currently in the controller all right so we’re going to visit again of course and one thing I like to show here that you might actually disagree with is I times see the test as it tells a story and sometimes when I tell or I want to help tell the story better I will illustrate it a little more verbose Lee than I would in production code so in this particular test I’m actually going to have like a pre assert that when I start this test I have one assigned and then three unassigned items then if I click the unassigned cards equal zero basically the zeroed item in that list and then we’ll have a new thing that will call the assign button here that if I were to if I were to assign click this button and actually assign one the end result and the reason I say this is kind of like telling a story because I can see the before and after in the story here so I should go from one and three to two and two and this is actually gonna be cool because we’re gonna see a couple different ways I use the test to give me feedback the first one is there is no assign button found and it actually blows up on the test runner so we need to flip back and to the handlebars side just add a button here give it a class of sign button and we’re just rerunning the test knowing that we’re not complete but we’re gonna hopefully get a different error message meaning we’re heading down the right direction we are so we’re getting expected two and three have not been remapped so the first thing is we’re just gonna fire this action of a sign off here we’re gonna pass along the to do that we have that we’re currently looping over and in the controller we just need to actually add in actions block now and say a sign is a function that’s going to give us its due and of course the simplest thing to do in here is really just set that status code to a two for the moment now what’s interesting is the tests are still failing and if I got this far and I wasn’t the programmer who wrote the original computers I might be a little confused but as somebody called out earlier really what’s missing here is the ability to break the cache one status code is updated here so I just tell the computer properties one to break and now when you click that blue button it officially moves them from left to right which is cool alright so one thing I just remember it is we have this hard-coded model data and most times this the night very next progression here is to actually do some kind of Ajax call and get this data from way back in so let’s just work towards that migration and figure out how we’re going to mock the xhr the first thing I’ll do assuming I’m not using ember data here for whatever reason is I’m just going to get an array of two do’s and return get JSON say API to do’s and all we’re gonna really do in the end is return these to do zone this promise resolves or this deferred and we’re gonna do is loop over so do a for each here get this data and all we’re gonna do is say to do is push object to do create passing that data for now basically simulating we’d probably do in a real app now of course I take that out we’d expect the world would end on the test side and it does and now we need to do is just stub that there’s a whole bunch of libraries out there that let you stub this there’s

mock Jax and pretender I’m actually just gonna use one called faux Jax I won’t be religious about it and I’ll just say it’s easy to use so I’ll say faux Jack’s new and all I have to do is give it the API to use endpoint and the response text whoops and not create to Do’s that would probably be a win these are actually need to be similar to what you’d send on your back-end here which is just raw JSON and now that gets our test passing which is awesome so now we have more votes a real app our route as actually reaching out to some kind of back-end and fetching this data and there’s really only one test left to right and that is clicking the toggle link will show details for given item and this one we’re just going to start out by doing a visit of course and this one actually is kinda interesting is I expect just to click this button so I’ll go to the unassigned category again cards equals zero and I’m gonna go to this toggle link thing that doesn’t exist yet oh base could be a link a link to helper and then all we’re gonna do in the very first assertion is just assert equal that the current URL has changed and we’re gonna expect that to be something like to do one because it just happens to be first in the list and the first failure we get just like earlier when we tried to do the button is the toggle link is not found at all so I’ll go back to the handle bar side and just say okay well it had a link to here we know it’s gonna be an href and we’ll probably do something like two dues dot to do is the URL and pass along our friend to do and then make sure we get our CSS selector right we’ll pass in the toggle link here and that is a link to now the very next error that actually confirms and lets me know that I’ve clicked this is that it blows up and says hey Turin there’s no route to dues dot to do so which is great because the router hasn’t been magically set up behind the scenes for me so we’ll go actually add a nested route here or just call it to do and give it a path of slash to do slash to do underscore ID and now I should get a different error and notice the error here it’s actually something I wasn’t expecting the first time I wrote this talk is I was expecting just to work but of course there’s no ID property so assuming on the back end we’re actually gonna get an ID we actually want to have probably some incrementing IDs so we had IDs one two three four now and the test passes stoical all right that’s not it if we look at the production app here when I drill down it’s great that first the URL has changed but you’ll notice this entire column on the right this kind of details column originally when you load the page if I go back here if I go back you load the page it’s actually hidden so I wanted kind of a cool user interface that would just let me stay on the same URL but then show this details list so the first thing I’m wanting to actually do is say that there isn’t there is a details section but it’s hidden by default so I’m going to do that actually in a kind of prerequisite assert kind of like we talked about a little bit earlier and just say details is we’re gonna find something called details section and we’re just going to do an assert dot okay that details is hidden because we expect it’s hidden when we hit the page and of course we blow up the funny thing is we’re actually blowing up not because it’s not hidden it’s just not in elements really at all so we’re getting that truthy argument so if I create a div here and give it a class of details section and then I’ll just make it hidden by default just to kind of get us rolling here running out of time the next thing I want to do is the whole reason I set that up is in the end here actually want to say that once I toggle the URL that it’s not hidden that’s the whole point right so I can toggle this details link basically and you’ll see well we haven’t satisfied that because in the handle bar side the first thing we need to do is actually make this dynamic so we’ll do a bind adder and do a class where we always have details and then whether or not hidden is there is actually based off the is active route so we’ll say is this the active route and if we’re gonna have this is active route we’ll go back to the controller here and just add an is active route and we’ll just do an ember computed equal and really what we’re after here is current route name and if that is equal to to do index we know

we’re in the parent route unfortunately current route name doesn’t come for free I actually need to hijack an application here and do controllers stat application current route name once I wire that up the tests are passing and the very less very last piece that’s going to get us going here is that I also expect that there’s a bound input so I’ll just call this project input basically find within the details section and input with the class of project and doing assert that equal that projects input that val is equal to first which just so happens to be the text is our models first project so now what we need to do to make this happen is go back to the handlebars add an outlet once I add the outlet I just need to add a parent template to dues that’ll let me add to do HPS once I have to do HBS I can do an input class project and the value is simply model dot project but let’s not drop the mic yet so that’s that’s the functionality right that’s sweet but what about how does it work does it really work so we’ll go out to our ember CLI app here and here’s the app I have this little X link that when I click it changes the URL it updates my bound property I have these buttons that are not very pretty right now but they work and I have the skeptical block skeptical developer on my team this is torn these tests are great but as soon as we have that designer come in it’s over so let’s prove that guy wrong right now so I’m gonna do ember server here and this is basically with only HTML changes so and I actually do work with a really great front-end guy he’s not the pessimistic guy what that was fictitious but he’s really great guy and let’s just say he came in and designed this for me which I’m kind of a scumbag that way I’m always like hey it’s done would you you know make it look great that’d be sweet so you can come in and you can come in and still click click around you can still click get the details the details are still bound what about those tests I think those tests still work