Test Naming
23-09-2025
Since my first line of code, I've always wondered about better ways to name tests. Naming is closely related to software design, capturing knowledge in code. In this article, we'll see examples that illustrate important topics when trying to shape our tests.
But first, I'd like to remind you that our tests are the living documentation of the system's behavior, so taking care of them will help us maintain healthy software. However, this is a double-edged sword, because it's not always the case that they help; many times they slow us down more than the production code itself. We can illustrate this with the following example:
class TestCalculation: def test_calculate(): // code goes here...
It's curious how code can generate more questions than answers. I ask myself: what does it calculate? If it fails, what has failed in the calculation? With this, I want to illustrate that if we see in our test suite:
❌ TestCalculation::test_calculate
We are forced to cognitively load the content of this test, which most likely encompasses many concepts to save some development time. Another disadvantage is that after a few days, you'll start to forget what it calculated. Then the need arises to do it better and we get:
class TestInvoiceCalculation: def test_given_four_products_when_calculate_the_total_then_substract_the_discount_and_apply_taxes(): // code goes here...
This is an example of a test convention composed of arguments, the function under test, and the expected behaviors. These conventions often fall under their own weight because if we change the calculate
method, we'll have to change all the test names that reference it.
💡 In the book The Memory Illusion it's mentioned that we can only handle 4 to 7 pieces of information, so if we don't get to the point in the name, we'll start forgetting pieces.
If you find it difficult to name the test, remember that they can always be changed later. For example, it's very common in functional tests not to leave any detail out. It helps me to remove details like given_four_products
doesn't tell me anything in the name, since if I look at the test I can see it. We can infer the business rule that if there are several products there might be a discount and start enriching the test by removing everything irrelevant.
class TestInvoiceCalculation: def test_calculate_the_total_then_substract_the_discount_and_apply_taxes(): // code goes here...
On the other hand, it seems too long. Let's notice the and - it seems that when trying to name it, we realize we're looking at two different things in the same test: substract_the_discount
and apply_taxes
. The solution is simple: by duplicating code and looking at two different things, we solve the problem.
class TestInvoiceCalculation: def test_calculate_the_total_then_apply_taxes(): // code goes here... def test_calculate_the_total_then_substract_the_discount(): // code goes here...
Let's solve problems little by little. For example, the class name - we can play with it both to give context and readability. The idea is for it to be easy to read like a book along with its methods, which are the system actions without going into detail:
class InvoiceCalculationWhenCalculatesTheTotalShould: def test__apply_taxes(): // code goes here... def test__substract_the_discount(): // code goes here...
The tests would be read from the terminal as:
❌ InvoiceCalculationWhenCalculatesTheTotalShould::test__apply_taxes ❌ InvoiceCalculationWhenCalculatesTheTotalShould::test__substract_the_discount
I chose Python because there's a limitation with names that forces you to put test_
as a prefix for each test method. As retaliation, I put two underscores to separate my rule from the technological limitation.
If you look closely, I've sought the option that gives me the most readability. For example, in JavaScript the sentence is much easier to construct thanks to Rspec's influence:
describe("Footer should ", () => { describe("on both window sizes", () => { it("copy the email to clipboard", () => { //...
Don't settle for letting bad names pass; they will haunt you and make you want to delete them rather than maintain them. Think that test code is as valuable as production code. First agree on some rules with your team and enjoy the process. I'll sign off by leaving some resources.