CleverLabs
Apr 26 · 3 min read

There are a lot of ways how to write good tests, but there are always some specific cases which can’t be easily described with widely-used guides. And of course you always need to keep in mind a lot of things when you writing tests for enterprise applications. So I’ve put the thoughts in a 6-point-list on the good approaches to write better tests and I want to share it with you.

First of all, let’s start with the ground rules. I would prefer to stub all the things. Yes, it’s a little bit too aggressive, but it’s about unit tests, after all. I’m pretty convinced that mocking is good, of course, you have to have integration tests (assuming, that everybody knows about the testing piramide or the testing trophy for frontenders).

I haven’t noticed a lot of enterprise projects with TestUnit, Minitest or ActiveSupport::Testing. So, I will mention RSpec as a standard for Rails testing. RSpec provides a lot of different APIs to allow testing your code at any layer. I would recommend using rubocop-rspec to adopt community best practices on writing good test. But, unfortunately static syntax analysis isn’t just enough.

So, here are the top-6 good approaches we use to write better tests with RSpec

1. Use FactoryBot for models

Prefer to use FactoryBot over instance_double with model class. FactoryBot provides a full-featured model with attributes, columns and so on. build, build_stubbed and even new methods prepare a Model stub, not a generic class double.

2. Use correct type of test-doubles

It’s better to avoid usage strings as an argument for instance_double or class_double. In the first example, developer stubs a method (namely non_existing_scope) which does not exist, but RSpec is unable to detect contract vialoation. Better approach is to use class_double with relation class.

3. Use doubles declaration to stub calls

Prefer not to overuse expect(smth).to receive(smth) construction. The main idea is to use double definitions instead of mocking it in before block. It makes definition more concise and respects code locality principle.

4. Group stubs definitions

It may be a good idea to separate DB-related stubs and other service stubbing. You can clearly see that DB-related stubs are at the top group and services stubs are in the group bellow.

5. Do not use any gem to emulate workers calls

There is no need to use any libs to run simple workers (especially with ActiveJob). Workers are just Ruby classes, right?

6. Do not stub Time/Date

There is no need to use Timecop. First reason is — you can use default Rails’ travel_to. The second reason (more important one) is that you can use the dependency injection pattern for this. Moreover, some libs relay on Time class to measure tests duration.

Summary

There are a lot of ways to write good tests and neither of them is ideal. The ones I have listed look pretty reasonable and allow you to write more maintainable tests. And of course, use the ideas I have mentioned above and share your ideas on how to improve them.

CleverLabs

CleverLabs is a software engineering and IT consulting company. It focuses on developing web applications for businesses. The company provides custom applications development in a variety of fields: HRM, EDI, eCommerce, healthcare, blockchain storages, smart contracts and others.

CleverLabs

Written by

CleverLabs

CleverLabs is a software engineering and IT consulting company. It focuses on developing web applications for businesses. The company provides custom applications development in a variety of fields: HRM, EDI, eCommerce, healthcare, blockchain storages, smart contracts and others.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade