We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
Analysis Summary
Worth Noting
Positive elements
- This video provides a clear, practical demonstration of refactoring and anonymous function syntax in Elixir using a concrete coding example.
Influence Dimensions
How are these scored?About this analysis
Knowing about these techniques makes them visible, not powerless. The ones that work best on you are the ones that match beliefs you already hold.
This analysis is a tool for your own thinking — what you do with it is up to you.
Related content covering similar topics.
Episode 1: Handling Unexpected Errors Gracefully
Exploring Elixir
Exercism Summer of Sexp - solving challenges with Clojure
Practicalli
Understanding Core Clojure Functions Jonathan Graham
Zhang Jian
"Clojure in live sports television" by Christoph Neumann
ClojureTV
Why Prismatic Goes Faster With Clojure Bradford Cross
Zhang Jian
Transcript
we've briefly covered tests in previous episodes but I've never explained them in depth today we're going to look at writing unit tests and learn a bit more about X unit let's get started testing is one of the most important tools in a software developer's arsenal it's also one of the most underused historically although things seem to be getting a lot better on that front lately today we're going to cover what is testing and what is it good for X unit elixirs built-in unit testing framework we'll build an example module via test-driven development and we'll look at a great feature elixir provides called doc tests so what is testing good for well people often see testings value in avoiding regressions and that's a fantastic reason to test tests also allow you to refactor your code without concern that you've accidentally changed behavior in some subtle way I see an even greater value in testing as the way to plan the code you're going to write testing is how I think now and I find it easiest to build a system by gradually writing and satisfying a series of unit tests test-driven development also provides valuable feedback that helps you know when a module in your system is getting too complex if the tests are getting hard to write the odds are your code is doing too much the time between when I learned how to test in Erlang and I built a working chat server was just a few hours unit testing is a means of testing just a single unit in your system and this can be contrasted with an acceptance test which tests the behavior of a system as a whole and verifies that it satisfies the overarching requirements unit tests are focused on a single portion of the system so that a single portion of the system can be verified alone let's have a look elixir comes with the built-in tool for writing unit tests called X unit you've already seen X unit test cases in previous episodes let's start a new project and talk through a bit more we'll look at the auto-generated tests here we can see a test case that was already created for us I'll comment out doc tests for now we'll come back to this the test is fairly self-explanatory it has the name the truth and it asserts that one plus one is equal to two let's talk about assertions assert here is a macro provided by X unit to describe the intended behavior of your system what happens when an assertion fails well test that one is - we'll run the suite and this test should fail and we can look at it and we can see that test one is - assertion with equal failed it says the left was one and the right was two so you can see very clearly what the differences if this were more complicated the red and the green would show the differences okay so the inverse of assert is refute so we'll refute that one is - and that test these two macros provide most of what you'll need to write your tests there are a few other assertions provided and you can check them out in X units assertions documentation which I've linked to to get comfortable testing in elixir we're going to create a module of our own using test-driven development or TDD if you're unfamiliar with the concept it's basically the idea that you write your tests first and then you write just enough code to make them pass and no more that is you let the test drive the development of your codebase we're going to test drive our schizo module it's going to provide two functions uppercase and unvail these functions will uppercase every other word and remove the values from every other word respectively since we'll be using TDD we'll start with the tests let's define some behavior for our first function uppercase so we'll get rid of the existing tests and we'll test uppercase doesn't change the first word so we'll assert that when we call skitzo to uppercase on foo it's just foo next we'll test that uppercase converts the second word to uppercase and then finally we'll add a third test that says uppercase converts every other word to uppercase so this is enough for now let's just start implementing making tests pass one by one as we go we'll start by making the uppercase function so we'll open up Lib skitzo get rid of the auto-generated bit and we'll define uppercase it takes a string our first test says that it doesn't change the first word so we'll make the simplest thing that will work so we'll just return what were passed if we run the test now we can see we had three tests but two failures so the first test passed now we can move on to the second test case and the second word should be uppercase what we'll do is we'll split the input string on space and we'll uppercase every item in the list to start and we'll join it back together with a space so this is not going to work but this is a step so we'll come back here we'll take the string well pipe it through string dot split on space I'll pipe that through enum map have a function that takes the word and then calls string that upcase on the word loop and finally we'll go through enamine okay we can run the tests and they fail but if we look they fail slightly differently right now we're upper casing everything here we're using enum map to map each item in our list through a function we really only want to map every other word and there's sort of a function for this there's enum map every so let's try to use that instead so we can map every and you can say every how many so every two words and we'll run it and it almost works so if we go back we can see that it's actually upper casing the inverse of what we want the opposite of what we want but it's neat to see that function we want to map to even words so we can't use this we can use another function from enum though it's called enum dot with index so we'll undo we use enum dot with index and with index we'll convert an enumerable into a list of two tuples where the first element is the data and the second element is the index in the enumerable and then we can apply our function to every other word so we'll map will go through enum dot with index so we end up with a list of two tuples and now when we map will be getting a to topple the first is the word and the second is the index so we'll pattern match those out and here we'll say let me break this up a little bit here we'll say if even then return the word otherwise return string that up case on the word and then we join and if we run the test now they pass so with that we've implemented upper case so now let's implement on Val first we'll write some tests and I will copy and paste them because they're gonna be very similar change all of the cases of upper case to on Val and unveil removes the second words vowels and it removes every other words vowels and then we'll fix these it's foo foo bar foo foo BR and foo bar Baz we would be food BR Baz WH so once again we can run the tests and of course there's no unviable function so we'll go ahead and create an unveiling and we'll start off like we did before just taking the string and returning it we found ourselves in the same situation as before for the most part right we know we're doing something with every other word so we'll just paste this bit down here and change the bits that matter so instead of string that up case we will use reg X that replace will replace the regular expression that just has a e i o u we have nothing and then that should work so let's run the tests and they all pass so we're done right not quite TDD consists of red green refactor so far we've just done red green so we've made tests that failed and we made them pass there's a lot of duplication here though and removing it will teach us some fun stuff about elixir so let's go and refactor this until we're happy with it the whole point of the test is that now we can do this without fear we'll start by adding a new function every other word and it's going to take a string and a function to perform on every other word and we'll just use it on uppercase to start so we'll say every other word we want to do something with this journalist a string piped through every other word and we want to do something let's go ahead and pull this down to that function and we can see pretty clearly what needs to happen here right so the function needs to get called on the word here and so then we'll just pass in a function that works so we'll pass in a function and takes a word and then just calls string that up case on the word and then we can do the same thing for unviable well let's go and run this test first and it works okay so let's do the same thing to unveil where our function is going to be that regex replace and I'll break it onto a separate line we can run the tests and they pass that is already a little bit nicer and it works so there's still a bit we could do to clean it up elixir provides an operator the ampersand that makes it a bit easier to produce anonymous functions from existing functions so we use that to extract string that up case to see how it works here you can see we've made a function that basically just calls string that up case and so if we could just use string that up case here would be nice so we can use ampersand to extract string up case 1 and that works so that's how ampersand works just gives you an anonymous function that does what that function did and then we can use a pipe to make this read nicer we've already done that so originally without the pipe it would look like this but I went and did that anyway so this is nice so we can't just extract reg X dot replace because it doesn't take a single string argument so we can't just do that instead we have a few options we could produce an anonymous function with ampersand and pass numbered arguments into it and this is kind of weird but I'll show it to you it's not weird it just maybe is not so straightforward so we'll say the first argument goes here in this anonymous function we just extracted and I need actually sorry this FN word needs to go okay so this may not be very clear let me back this up so here we're saying we want to extract a regex start replace we want to go ed and fill in the first argument and then we'll take whatever argument were past and put it in the second spot and regex die replace so this is just making that function that we created before but if you don't love the way this looks I am fine with it if people that I'm working with understand elixir pretty well and these days that's pretty pretty much everyone that's been working with it for a while but even still you might find it nicer to have code that reads like this so if we just comment that out and if we said every other word just remove the vowels has the nice benefit that it's clear what you're doing without having to read through and figure out what it does and so if we want to do that then you can just make a remove vowels function that takes a word and just calls regex to replace so this is the sort of the innards of what we had before just extract it to its own function and now it passes and if you read the code it's pretty clear right you take the string and then every other word you upcase or you take the string and then every other word you remove the vowels I think it reads really nicely so either of those last two approaches is acceptable I think the second is a bit more self documenting and that might be nicer to people that are reading your code later I think it's a good idea to optimize code for easy reading since you're gonna spend a lot more time reading code than you do writing it at any rate now we're left with something quite nice looking and it's very easy to extend it with more functions along the same lines we just need to define the transformation functions and we're basically done elixir also ships with support for something called dot tests basically the way this works is you place an example ie X session in your module or your function documentation and then you can easily verify its behavior by specifying a doc text test in your test case so this was cribbed from Python but coming from Ruby I never had a chance to play with it before I started playing with a lick sir and I think it's amazing let's go ahead and add a doc test to the schizo module so you can see how it works and you can also see how to document a module here so we have module doc and we'll put a here doc here and then we'll write some documentation so this is a module that provides odd behavior for transforming every other word in we can say here are some examples and then I'll tab in a little bit and do an IX session right so schizo dot upper case this is an example and then I can show the return value which would be this is an example I can do the same thing for unveil a B this is an example and then so now we've defined this so this is defined our documentation but to add them to your test suite you just want to open up the test module and we'll add back the line that was removed originally so this is doc test kit so if you just add that now when we run the tests we can see rather than the six tests that we defined we've ran eight tests so we ran the to IEX sessions as their own tests and if they failed which we'll do we'll come in here and we'll say I'm gonna make this fail or run the tests and now we've got a failure inside of our documentation test so that's really nice now you don't have to deal with documentation that's subtly incorrect someone writes doc tests and their tests pass then their documentation is accurate today we learned how to write unit tests test drive a module from the ground up and we explore doc tests armed with the ability to test drive your code you should be able to level up and elixir substantially faster from here on out see you soon
Video description
An in-depth look at ExUnit, Test-Driven Development, and doctests. Check out dailydrip.com for more videos and tutorials just like this!