How do I start testing a large rails application?

I wanted to learn Ruby and Rails and had failed in the past, so I created a prototype for work that generated PDFs from simple scaffold of our products. I presented this concept to my boss, and he has allowed me to write ruby ever since, which was a huge win for me.

About a year and a half later I have released the next iteration of our company website written in ROR. I am a dedicated learner, but learning ruby, rails, terminal was a lot for me to take on at once, so when it came to testing, I figured I would just punt the subject and come back at a later date. I have generated many scaffolds in the past, so I unknowingly had a huge test suite of hundreds of failing tests. I tried to isolate and get various test to pass, this quickly became overwhelming as I was unable to accomplish anything meaningful and eventually quit due to frustration and lack of productivity.

I would like to try again and am looking for suggestions - I also just signed up for Upcase and began the ‘test driven rails’ trail. My initial thought was that I should delete all the generated test code and start from scratch. This seems to me like it would be easier as I could slowly build up a test suite starting with the most important models/functionality first. This way I could expand coverage as I learn and have some success I don’t get stuck and overwhelmed.

Does anyone have an opinions or advice on my initial plan? Has anyone gone through a similar experience? I would really appreciate any advice anyone could provide!

Thanks,
Thomas Bush

You’re going to start doing testing in this app the same way you eat a whale: one bite at a time.

Pick a part of your application (let’s say models to start) and then pick a single class in that portion of your application. Preferably this should be a class that either has problems, you’re planning to refactor, or is going to have new or changed functionality in the near future.

Fix the failing tests.

Identify the parts that are going to change next, and write tests for your new functionality that fail. Write code that makes those tests pass.

Forcing yourself to write failing tests first feels pedantic, but it really does protect you against writing tests that give you “false positives”, tests that pass even though they shouldn’t. It can be quite easy with mocks and stubs and doubles to inadvertently create a test that tells you nothing when it passes.

You can’t just suddenly start testing everywhere, but you can start consistently making the testing situation better and not letting it get worse by using tests every time you change your application from here forward.

This is a reminder that there’s some awesome testing content out there. thoughtbot has a book in beta written by @jsteiner and @joelq specifically about testing Rails applications that you might find useful.

Thanks @geoffharcourt. This makes sense, but for clarification, does that mean you would recommend I attempt to fix the broken generated tests? Or start from scratch?

1 Like

Tests generated by scaffolding or generators are not likely to be very useful, especially as you’ve moved beyond the scaffolded code in your classes.

If you’re just looking to comment out noise you might want to put skip or pending (for RSpec, would be different for other testing frameworks) into your tests so you know you’re missing tests, but you don’t get a huge board of red every time you try to run your suite.

It’s probably fine to just replace those files one by one as you write real tests, but editing the ones in place is OK too. The point here is just to start getting from zero to something. Get some quick wins, start building some testing momentum so that writing tests becomes habit, and your application starts moving into solid testing over time.

I was in the same boat as you @ThomasBush - I was 12 months into a live project before I started to add any significant tests. I was learning Rails on the job and testing felt like too much to take on at the start but I’m adamant about it now, using TDD whenever I add new features or change code.

I found this book to be very helpful at the time: Everyday Rails Testing with… by Aaron Sumner [PDF/iPad/Kindle]

I started from a clean slate - deleted all the scaffold generated tests and moved to using RSpec, Capybara, DatabaseCleaner, etc.

The approach that gave me the most bang for buck initially was to add high-level integration/feature specs. Write tests for the main actions a user takes in your application - in my case this was signing up, signing in, adding other users, creating the various resources that my users can create when signed in.

When I was starting out my tests were littered with expect(page).to have_content 'foo' at every stage because I wanted to be certain the path through the action was correct. Eventually I left these out and got more confident with my spec writing.

I agree with @geoffharcourt - avoid writing tests that give ‘false positives’. Intentionally break your tests, make them fail and read the failure message and expected/got results. I found several cases where a simple test was passing but not for the reason I thought it should.

2 Likes

@weavermedia makes an important point: if you’re retroactively writing tests, make sure they will fail by temporarily breaking your application code.

Thanks @geoffharcourt and @weavermedia - your suggestions help me out a ton. I will have to check out both of those books.

1 Like

I’d also take a look the source code for discourse and just pick either a single model or a controller. Most of the books on rspec I feel spend too much time on simple cases when testing is really very straightforward. For example, look at t at https://github.com/discourse/discourse/commits/master/spec/models/user_spec.rb . This way you can see the FULL history of how these were refactored and tested over time. Much more valuable in my opinion.