DEV Community

Cover image for "You Don't Know Java" ๐Ÿ’˜ The Philosophy of Unit Test Naming
Chuck1sn
Chuck1sn

Posted on

"You Don't Know Java" ๐Ÿ’˜ The Philosophy of Unit Test Naming

The Design Philosophy of Unit Testing

Programs are written primarily for humans to read, and only incidentally for machines to execute.

Programs must be written for people to read, and only incidentally for machines to execute.

The first step in writing code is naming, and the same applies to unit tests.

WWW

How can you make the names of your unit tests understandable? You need to reflect three elements in the naming, abbreviated as the WWW principle.

  • What are you testing? (what)
  • Under what conditions are you testing? (when)
  • What behavior do you expect? (want)

Let's take a look at a unit test example from the MJGA scaffolding.

  @Test
  void createVerifyGetSubjectJwt_givenUserIdentify_shouldReturnTrueAndGetExpectIdentify() {
    String jwt = cookieJwt.createJwt("1");
    assertThat(cookieJwt.verifyToken(jwt)).isTrue();
    assertThat(cookieJwt.getSubject(jwt)).isEqualTo("1");
  }
Enter fullscreen mode Exit fullscreen mode

Breaking down the name into three parts:

  • createVerifyGetSubjectJwt reflects the object being tested.
  • givenUserIdentify indicates the condition under which the test is conducted.
  • shouldReturnTrueAndGetExpectIdentify describes the expected behavior.

This is a good nameโ€”one that a business person can understand.

AAA

The first hurdle is over; now let's implement the test logic. In fact, with the WWW naming design, the logic implementation already has a clear path. Like naming, test logic also has principles to follow, commonly known as the AAA principle.

  • Arrange
  • Act
  • Assert

Let's continue with a test case from the MJGA scaffolding:

@Test
  @WithMockUser
  void signIn_givenValidHttpRequest_shouldSucceedWith200() throws Exception {
    String stubUsername = "test_04cb017e1fe6";
    String stubPassword = "test_567472858b8c";
    SignInDto signInDto = new SignInDto();
    signInDto.setUsername(stubUsername);
    signInDto.setPassword(stubPassword);
    when(signService.signIn(signInDto)).thenReturn(1L);

    mockMvc
        .perform(
            post("/auth/sign-in")
                .contentType(MediaType.APPLICATION_JSON)
                .content(
                    """
                {
                  "username": "test_04cb017e1fe6",
                  "password": "test_567472858b8c"
                }
                 """)
                .with(csrf()))
        .andExpect(status().isOk());
  }
Enter fullscreen mode Exit fullscreen mode

Arrange

This is the preparation phase of the test. In this phase, you need to construct some code that provides context, such as inserting data, building objects, or even more complex mocks and stubs. In the example, we constructed the SignInDto object for subsequent use and assumed the return value of the signIn methodโ€”all in preparation for the subsequent test.

Act

This is the execution phase, corresponding to mockMvc.perform in the example. The API is just a bit complex here, so you can think of it as a single line of code.

Assert

You need to clearly state what result you expect. In the example, this corresponds to .andExpect(status().isOk());.

Often, you may need to write some test methods to verify whether a certain logic can run without errors, as the method itself has no return value. This is easy to solve using assertDoesNotThrow.

 // pause & resume job
    JobKey firstDataBackupJobKey = dataBackupJobKeys.iterator().next();
    assertDoesNotThrow(
        () -> {
          dataBackupScheduler.pauseJob(firstDataBackupJobKey);
          dataBackupScheduler.resumeJob(firstDataBackupJobKey);
        });
Enter fullscreen mode Exit fullscreen mode

These coding philosophies are independent of the language and framework you use. Any unit test is written with this mindset. More content on unit testing will be shared in the future.

Final Words

  • I am Chuck1sn, a developer long committed to promoting the modern JVM ecosystem.
  • Your replies, likes, and bookmarks are the motivation for my continuous updates.
  • A simple triple action (like, comment, share) means a lot to me and is greatly appreciated!
  • Follow my account to receive article updates as soon as they are published.

PS: All the code examples above can be found in the Github repository. If it helps, please give it a Starโ€”it's a great encouragement to me. Thank you!

Top comments (0)