Feature Tests vs. Integration Tests vs. Unit Tests
YOU SHOULD BE TESTING! — Every Rubyist
Testing is important; you hear that a lot in the Ruby community. And not without good reason.
Why is testing important in Ruby?
If you’re coming to Ruby from a different language, you’ll immediately notice that Ruby is a very permissive language because of its duck typing. That’s a good thing because you can quickly build a proof of concept without worrying about all the details up front, but it’s also a bad thing because code that gets built like that is usually far from perfect.
The trick is to realize what you’re doing and choose the right tool for the job. Testing is one of those tools. It allows you write better code, while also providing documentation for it.
If you’re building a customer-facing application, you’ll probably want to write code that will last for years. And I don’t mean you will put it out there and never touch it again. I mean code that will be easy to change however often the market demands it.
The different types of tests
I’m sure you’ve seen the many types of tests that the Ruby on Rails framework comes with, and you’re probably wondering if you have to learn all of them to be able to write production-ready applications. And the answer is… yes and no.
They all fit into two just two kinds of tests. Integration tests, and unit tests.
What are integration tests?
With integration tests, your goal is to simulate a real-world scenario in which many units of code collaborate to deliver some value. Another way to look at it is making sure all the units work together as a whole. That is because while each unit can function independently, it must also collaborate correctly with others.
What are unit tests?
Unit tests make sure that every unit of code functions correctly in isolation. The reasoning is that if every unit does its job correctly, then it will be easy to compose units together (like Legos), to create an application.
Feature tests vs. request tests vs. unit tests
Because you’re going to encounter these names a lot, let’s see what they mean and how you should use them.
With feature tests, you are testing the application by interacting with it just like a real user would do. So they are integration tests.
You click on links, buttons, fill in forms, interact with popups, etc.
Feature tests are all about what the user CAN see.
They give you the most bang for your buck in the sense that they make sure your users get value out of your application. Or from a different perspective, you are making sure the application is not broken in such a way that a user might notice.
Because feature tests need to mimic the user’s behavior as much and as close as possible they are using a web browser to do their work and that is very slow, which is their biggest downside.
Request tests are still testing your application end-to-end, but they focus on the things that the user cannot see. For example, things like records being added to the database, or assertions about HTTP request status codes, redirects, calling 3rd party APIs, etc.
Request tests are all about what the user CANNOT see.
Because you’re not using a browser to drive these tests, they are much faster than feature tests, but still a little slow because of they do need to talk to the database.
With unit tests, your goal is to drill down into each piece of business logic you’ve got and make sure it behaves as it’s supposed to in every context you can think of.
Unit tests are about domain logic and edge cases.
They are also really fast, and if you manage to write them in such a way that they are isolated from everything else (like other objects, or the Rails framework), you get instant feedback from your tests, which is pure joy. Having instant feedback and relying on the test to tell you where you need to go next, makes writing code so much easier because you don’t have to keep all the context in your head. You can safely delegate it to your test(s).
Pros and cons of the different types of tests
|Feature tests||Your users won’t see a broken app||Very slow|
|Request tests||Your app will work beyond what users can see||Somewhat slower|
|Unit tests||Your app can handle edge cases||Won’t guarantee all the pieces work together|
Using the different kinds of tests in your Ruby on Rails application is somewhat of a balancing act where you need to trade coverage for speed. You want your entire test suite to be fast so you can run it often, and you want your application to be thoroughly tested so it can be easier to change.