How to name a unit test when using TDD?

Asked

Viewed 2,984 times

8

It is common to use nouns to name: classes (Car, Vehicle, Notafiscal); action verbs (infinitive or not) for method names (Calculartotal/Calculatotal, Lertodasaslinhas, Closeconnection, Abra porta/Abreporta); interrogations for boolean returns (Enable, Mustcalculate, Shoulddosomething, Open, Shotgun, Stationary, Active). These are OMG recommendations (for UML).

But what about unit tests? Is there any standard, guide for naming unit tests?

The following are some examples of names I found in some codes I’ve been in contact with:

  • Should return to zero: does not say the situation, nor the reason, nor what is being tested, only shows the desired behavior.
  • Nao_deve_ter_sobre_nome_ao_informar_...: tries to describe a behavior, but these names usually get pretty big.
  • Intparse: in this case, it is a test for the Parse(...) method of class Int.

I’ve seen names separated by underline, without separation, but written in camelcase, and many other forms.

My question is: there are best practice guides/suggestions for naming unit tests when using TDD?

  • 2

    It seems that you already know several "patterns". The @Inert response outlines my personal form as well, in all the other ways I’ve used ( the ones you mentioned ) I found this more objective. Just an addendum, be consistent. If you choose a form, use it until the end, talk to your team and decide that with them. Don’t forget that TDD goes way beyond that, so be significant in the names, if you achieve this, the naming pattern will become just a supporting.

3 answers

9


Your question deals with two aspects of method naming; semantics and formatting, so to speak (classifications that I have just come to think of).

Formatting

The issue of formatting is simple:

  • something()
  • faceAlgumaCoise()
  • Facaalgumacoisa()

Formatting is agreed by the team and is easy to understand and maintain. I always propose that the team identify the culture of language and follow this culture. For example, in java the lowerCamelCase, other than C#, where the Uppercamelcase for method names, which is different from Ruby, where it is used Lower case with underline as a separator. But the final decision is the team and an automatic code analyzer can easily identify the code that is not following the convention.

What’s more important here about the formatting is that there is no convention for TDD. There is a convention for the team or for the project. All code must follow the convention, be it the production code or the test code.

Semantics

As we know, the name of a method must reveal its behavior, and must obey the business language (when it deals with business). And the signature of the method must ensure the abstraction of how the method works. The signature should reveal to the consumer everything he needs to know about the method without having to look at the code within it.

The unit test code has a different concept. The name of a unit test method does not have to accurately reveal the behaviour he expects, nor does he have to reveal the conditions, entrances and exits ("when. .given.then")!

Although the name of the method has to be significant, it is his body, the code inside, that will describe the conditions, inputs and outputs expected.

Behold this example:

public class JogoVelhaTeste {
    @Test
    public void naoHaVencedor() {

        String[] tabuleiro = {
                "X", "O", null, 
                "O", "O", null, 
                "X", null, "X"} ;

        JogoVelha jogoVelha = new JogoVelha();

        assertNull(jogoVelha.obtemVencedor(tabuleiro));
    }
}

When I want to know what determines whether there is no winner, the name of the method allows me to find it among the others, but to know in fact which input determines that there is no winner (in this case, a board with certain moves), and to know how is returned the information that there is no winner (in this case, the method obtainer returns null), I look at the code inside the method.

So the code itself within the method is the documentation of conditions, inputs and outputs. And it’s executable documentation! It will never be out of date, as with comments.

The article of Roy Osherove gives you some cool tips, but you don’t need a method called Sum_NumberIgnoredIfBiggerThan1000. It would be better to call Sum_NumberIgnoredWhenTooBig, which is probably significant enough. The entries, as I said, are described in the code itself within the method.

The test should not depend on comments

In this example, the author suggests a comment to describe the test. Ok, it’s not a simple comment; it’s . Net! But in the end it’s just a comment, which does not compile, which does not affect the operation of the test, and which may become outdated, and which will only be read as the developer’s last option when he is looking for an old code test (just as the developer can also read the code within the method).

Behold:

[TestMethod]
[Description("Given two tables And same data But different column order | When TableAssert | Then true")]
public void ColumnOrderDoesntMatter()

The name of this method is already quite significant. Dispense with the comment. The conditions, inputs and outputs can be checked in the body of the method itself, which the author of the example does not reveal but which well can be something like this:

[TestMethod]
public void ColumnOrderDoesntMatter() {
    
    Table tableAscValues = new Table("value 1", "value 2");
    Table tableDescValues = new Table("value 2", "value 1");
    
    Assert.Equals(tableAscValues, tableDescValues);
}

Bring back the comment (Description) for the above method would be redundant.

Behavior Driven Development (BDD)

BDD is different from naming the method in style when. .given. then. BDD is about writing tests with this semantics using an executable language. So, as in my example (which is not BDD), it is the body of the test method that says the conditions, inputs and outputs, and not the name of the method.

Choosing a test method name using TDD

In TDD we write the test first. Often we still do not know how the solution design will be - it will emerge from the tests. Then it can be very difficult to immediately choose a good name for the test. No problem. Choose any name that reveals more or less the intention of what you want to test, then write some more tests, then revisit all the newly created methods and refactoring them, including improving their names.

Completion

  • The format of the test method name (Lower Camel case, underline...) must follow the same rules as the production code. These rules are agreed by the team.

  • The name of the test method should be significant, it should mainly describe the business behavior that is being tested; but the conditions, inputs and outputs are described by the code within the test. A testing method does not have the same type of abstraction that must have the methods of the business objects.

  • The body of the test method is the executable documentation of system behavior.

6

There’s taste for everything, I’ve never seen a universally accepted standard. In that reply I put nomenclature standards well accepted because it was basically established by the company that created the C#language, making the necessary reservations. In this case I find it more complicated.

For TDD, which I have little experience, depending on the language may have small differences of pattern but I think what you want to know is something that can be applied to all languages save stylistic differences from using uppercase, lowercase, underscore, etc.

I have seen different recommendations. One of them is to describe what this test is expected to represent very succinctly. Another is to describe exactly what and how the method tests.

Particularly the first seems to me to be more sensible. The first examples you quoted seem to use the second form I quoted. I know a lot of people wear them like that. But it seems to be a case of people copying a form established in the past but that no one has given much thought to whether it makes sense or not. I have said many times that this happens a lot in our industry. There are people who still follow recommendations from the 1950s. Of course some may still be valid, but not all. Maybe it was because the tools were not good. And maybe some are not yet.

Then one must try to understand why the method must return zero and describe the motivation of the test. One should use a context. Who will say that should return zero is the code.

Some languages also allow you to have an attribute/annotation that allows you to give a detailed description of what the test does. It would be a comment that the tool will take advantage to help describe the test when it runs. Ex.:

[TestMethod]
[Description("Given two tables And same data But different column order | When TableAssert | Then true")]
public void ColumnOrderDoesntMatter()

The example was taken of that page. It shows how the detailed way of naming the method is worse.

I think so the programmer is doing real TDD. TDD should demonstrate what happens in the test and not how it is tested.

On that other page there is an analysis of the most used form.

2

I’ve been using the standard for a long time [UnitOfWork_StateUnderTest_ExpectedBehavior] presented in that historic article by Roy Osherove and cited in that answer.

To this day, he’s been applying himself to every case I come across. Of course, this requires the programmer’s ability to correctly model the unit to be tested, and if so, redesign its design to make it plausible. Even, this is one of the benefits of TDD, positively influence design.

Note that this pattern described by Roy can also be seen as follows [When_given_then], inducing us to develop our test method as follows:

UnitOfWork_StateUnderTest_ExpectedBehavior() {
    // Given
    // promova o estado sob teste...

    // When
    // acione a unidade de trabalho, ou o método...

    // Then
    // verifique o comportamento desejado...
}

Example of a Rocket class test (with Mockito):

decolar_tanqueVazio_permanecerParadoExibindoAviso() {
    // Given
    foguete.esvaziarTanque(); // foguete é uma mock instance em escopo de classe

    // When
    foguete.decolar();

    // Then
    verify(foguete, never()).iniciarDecolagem();
    verify(foguete, atLeastOnce()).exibirAvisoTanqueVazio();
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.