Testing, testing, 1,2,3... A Simple RSpec demo

I was once asked during an interview about my familiarity with testing. I was honest; it's something I'm familiar with (TDD, BDD, etc), and have had to read/run/pass a bunch (previously written for me) whilst at Learn Verified, but ultimately it's something I haven't had much experience WRITING ... yet. (And of course I added, "But I'm looking forward to learning more about it!", which is true). Side note: they haven't called me back...yet!

I just finished my Angular assessment. It went well but there are definitely some bits about my app that I will change, such as adding a review model in addition to my book model, so that one book could have many reviews. That's slightly annoying because it was how I originally set up my project. I should've listened to my gut.

Anyways, I appreciated the extra time and attention the examiner gave to go over testing. So I'm here to jot down some bullet points half for myself to remember everything we just covered, and half to share/introduce the ideas behind testing to you. I'll insert some screen shots where applicable. For this example, we used RSpec to test my book model. This example does not test Angular, though I'd imagine the same testing concepts apply? More on that later...

"RSpec is a behavior-driven development (BDD) framework for the Ruby programming language It contains its own mocking framework that is fully integrated into the framework based upon JMock." - Wikipedia
  • Testing is a way for you to literally test your code, making sure it works exactly as you expect. This seems obvious but the way to go about it is not, speaking for myself that is. What do I test? When do I test? How? Depending on the person, you'll receive a different response. If you are heavy into TDD, Test Driven Development, you will likely argue that you should write the test before you write the code, making sure it all passes along the way. Others seem to be more relaxed about it, testing afterwards. Some test everything, others don't. I'm not sure which category I'll fall into yet but I know that either way, testing is an important and helpful tool.
  • Testing gives you a chance to pretend you're a malicious hacker, (or just just an average user), entering all of the incorrect information. It's kind of fun because now is the time you can get creative and think up all the ways your app could go wrong. Now is your chance to efficiently enter bad information and find out how your code will respond. Will it respond in a way that you expect? If it doesn't, why not? Fix it. No surprises here! Defensive programming.

So for this example, we wrote sample code to test my book model. The code will return all the books if its rating is above a certain number.

The next screenshot is my seed file. You'll actually be testing dummy data, not the actual database.

After we got RSpec set up, we wrote a dummy test, "expect(true).to eq(true)", just to make sure it worked (it did). Then we got to writing a real unit test. For this, a "describe" block is set up. Inside of it, you'll declare a scenario and the outcome you would expect of it. In my first test, you'll see that we expected that out of all the books, only one would have a rating above three. If I wanted to take this test even further, I could've said which title that'd be. 

When we ran the test in the terminal this test failed, which surprised me.

I expected this test to pass, but had forgotten that we weren't testing my ACTUAL database; we were testing my seed file. This made sense because as you can see if you look closely, there isn't even a rating attribute in my seed file! So we added one to "current_book", and it passed! 

But actually, before this test passed, it failed again which surprised us both. This time it surely should've passed! Pry to the rescue! We placed a binding.pry in the test file, to check the data it was playing with. In this case, when we checked Book.all, we expected an array of my dummy data but received an empty one instead. hmmm...

The examiner helped here because there was actually something wrong with the way RSpec was set up. He added the following to my rails_helper.rb file, then it passed: 

"config.before(:all) do
    load "#{Rails.root}/db/seeds.rb"

We weren't done yet though! The second test we created to see what would happen if a user gave a book an "unacceptable" rating, such as a negative number.

Screen Shot 2016-04-21 at 3.33.25 PM.png

As you can see, out of the 2 tests/"examples", we have one that failed: "Book handles negative input correctly". This surprised me too, but did it really fail? I expected zero but got one, why? Perhaps this is the outcome I wanted... perhaps it's not. Do I need to debug this? This is an example where I can see what would happen on this particular scenario, and evaluate the outcome as acceptable or not. Perhaps I want to change my code to throw an error, not allowing negative number ratings. Or maybe negative numbers are OK because the book is really THAT BAD. That's the beauty of testing; they help to eliminate surprises and allow you to get quite intimate with your code.

In closing, if you're new to testing, read as many tests as you can. Thankfully I have loads of labs to consult as a refresher, but if you don't have access to that, Team Treehouse offers a great explanation about what RSpec is and how to write tests with it. Or checkout these docs. Also note that RSpec is not the only way to test.