I appreciated Adam's walkthru and approach to solving these problems using TDD, so I would like to attempt recreating his example in this blog post. If you'd like to follow along, after you've created an account and logged in, you can search for the "Boiled Eggs" exercise by clicking the icon underneath the red Code Wars logo.
The instructions state:
"You are the greatest chef on earth. No one boils eggs like you! Your restaurant is always full of guests, who love your boiled eggs. But when there is a greater order of boiled eggs, you need some time, because you have only one pot for your job. How much time do you need?
Implement a function, which takes a non-negative integer, representing the number of eggs to boil. It must return the time in minutes (integer), which it takes to have all the eggs boiled.
+ you can put at most 8 eggs into the pot at once
+ it takes 5 minutes to boil an egg
+ we assume, that the water is boiling all the time (no time to heat up)
+ for simplicity we also don't consider the time it takes to put eggs into the pot or get them out of it."
Immediately Adam directed our attention to the Test section, explaining that we should write our tests first so we know it will meet the requirements, vs manually testing with our code alone. Manual tests are inefficient and error prone, which explains the "why" behind the TDD concept. Code Wars usually provides pre-written tests but Adam encouraged us to write our own, explaining that a good test suite will be specific and ideally have 1 assertion per test, unlike what was provided to us below:
So let's rewrite our test suite, one step at a time! Because the site provides us with tests, it's pretty easy to use those as examples for writing our own. But there is a section of the site for test documentation with each language you choose. As you will see in the example below, we will pass a parameter to our cookingTime() function, which is the number of eggs we'll boil. The second number represents the number of minutes it'll take, and the last element is a string that'll read " # eggs" (which should match our parameter number).
So in the above screenshot we just separated the first test to be a test of its own, "it should take 0 minutes to cook 0 eggs". If you run this test as is, it should fail since we haven't written any code in the IDE yet. The results of the tests, by default, will replace the instructions on the left:
As you can see, our test states exactly what's wrong in a way that's easy to understand, because we've specified our test. It expected 0 and got undefined. So without overthinking it, how can we get our first test to pass? Let's simply give it what it expected and return 0.
Congratulations! We just passed our first test, using TDD! Let's think of our next test. We have 1 pot that takes 5 minutes to cook a maximum of 8 eggs. So let's make a test for that, 1-8 eggs! It'll look something like this:
Again, if you run the test now, only our first test should pass because we haven't written any code that could satisfy our new test. Try doing so now before looking at the next screenshot! Keep in mind that there are several ways to solve the same problem but our goal will be the same, which is to pass these tests before continuing on.
Fantastic job, but we are not done yet! Time to write our next test! This time you should think critically so we can be efficient. Sure, you could write a test for 11, 12, 13, 14, 15, 16, 17, 18, 19 eggs and so on, but it would be more strategic if you think about key numbers such as 16, 17, 24, maybe even 32. Why? Because given this example, we know that it'll take an additional 5 minutes for every 8 eggs. So at 9-16 eggs, it should take 10 minutes to cook. At 17 - 24 eggs, the eggs will be ready in 15 minutes. At 25 eggs, the time will increment again by 5 minutes, being ready in 20. Let's write a test to simplify that!
You know the drill now. If you run it, this test should fail as we haven't written any code for it yet.
You could split this test up so it will have one assertion per test, but I'm going to continue as is since I think by now you get the idea of TDD, and we are so close to solving this challenge! Now take a second to write the solution in the IDE to get this test to pass! We came up with the following:
Which can then be refactored to simply this:
Did you get it to pass? Good job! At this point, we can submit this challenge as we have satisfied all the requirements. But feel free to keep writing tests to play around some more. Test out an edge case for instance. What if the parameter we pass isn't an integer? Go ahead, write a test for that, then code in a validation feature for it to pass!
After submission, you are able to see other people's solutions which is always neat because you'll see that there are so many ways to solve the same problem. I always find comparing my solution with other's to be fun and interesting. And Code Wars even categorizes them, such as by "Best Practices" and "Clever".
In conclusion, I hope you found this to be helpful! Code Wars is a great tool and I plan to use it for my technical interview/whiteboard prep! I'm also excited to use it as a tool to practice testing too! (Thanks Adam!)