Why You Should Use described_class When Writing Rspec Tests in Rails

Daniel Pericich
3 min readJul 5, 2022
Photo by Jørgen Håland on Unsplash

Writing good, easily maintainable code should always include writing good tests. Tests, especially those written using TDD, perform a number of functions in shaping good programs. They challenge software engineers to think about outcomes and program uses before they start writing application code. They also provide code documentation of how new features should work along with specific passing and failing cases.

Good test code can quickly outnumber the application code it tests in terms of lines of code. It is not uncommon to write 3 times as many lines of test code as application code. This is normal and shows a rigorous set of checks being performed for expected behavior as well as edge cases. While large test suites are encouraged, writing lots of unnecessary checks is not.

I am always looking for new ways to say and do more with less in my code. One way to do this is make my code DRY (Don’t Repeat Yourself). Whether I do this by properly nesting shared factory values for multiple test cases, or placing repetitive test setup in a before block, cutting down on extra code should always be a driving goal. A way that I have enjoyed doing this recently is with the described_class method.

What is the described_class method?

Again, less is more when writing clear code. Repeating the same preamble for each test makes the tests clear in isolation, but will lead your code reviewers or future engineers to become very bored. To avoid this we can use RSpec specific helper methods to cut down on extra code.

An easy way to do this is remove extra declarations for the class under test, whether it be model or controller class. We do this by using RSpec’s described_class method. This method allows us to reference the first argument of the example group, removing the need to type it out every time we use it. For instance, with the following code snippet, we can use described_class instead of User::Address:

Figure 1. Using described_class with a short model name.

While this may not seem like a great savings, it quickly compounds as our namespaces expand. This is especially true when we are creating api controllers for use bexternal our app:

Figure 2. Using described_class with a long external api controller name.

Above we can see just how much typing and repetitive code the described_class method saves us. It pays to be clear, but also concise with your testing.

Flexible Design

One more advantage of using the described_class method in your tests is future name flexibility. When you are not sure of the final name of a model, or the final nesting of a controller in a file hierarchy, any changes can lead to a lot of name retyping.

By using the described_class method in your tests, any changes to the subject in test’s name will require only one change. Instead of changing the model or controller name everywhere it is used in the tests, you only need to change the name at the top level of your test file.

This will save a lot of time finding and replacing the old name, and ensure that you don’t throw errors for mismatched names in your CI system.

Conclusion

We should always be looking to make our code more DRY. Tests are no exception. While good tests serve as coverage to ensure our code functions correctly, they are also a form of documentation for future developers. If you are going to introduce described_class to your test suites, make sure you fill your team in on what it is and all the benefits that come from using it. If they need more proof don’t be shy in sharing this article!

Notes

https://relishapp.com/rspec/rspec-core/docs/metadata/described-class

--

--

Daniel Pericich

Former Big Beer Engineer turned Full Stack Software Engineer