Skip to content

Using TDD with the Help of Flow

React / Next

Example prompt:

Given the feature of adding a manager to a user through an autocomplete combobox followed by an MUI list where the selected ones are placed, give me the integration test for this feature for React using Vitest (testing library) following the principles of TDD.

The result is as follows:

// UserManager.test.jsx
import { render, fireEvent, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import UserManager from './UserManager'; // Importing the component

describe('UserManager', () => {
  it('should allow the user to add a manager and display it in the list', async () => {
    render(<UserManager />);

    // Step 1: Interact with the combobox
    const input = screen.getByRole('combobox');
    fireEvent.change(input, { target: { value: 'Manager A' } });

    // Step 2: Check if suggestions appear
    const suggestion = await screen.findByText('Manager A');
    expect(suggestion).toBeInTheDocument();

    // Step 3: Select the manager
    fireEvent.click(suggestion);

    // Step 4: Check if the selected manager appears in the list
    const selectedManager = screen.getByText('Manager A');
    expect(selectedManager).toBeInTheDocument();
  });
});

This prompt is efficient for several reasons:

  1. Clarity of Objective You clearly specified that you want an integration test for a specific feature in a React application. This helps to focus on the task without ambiguity.

  2. Specific Context By mentioning the use of an "autocomplete combobox" and an "MUI list," you provide a technical context that is crucial for understanding the libraries and components involved. This allows the response to be more relevant and targeted.

  3. Focus on TDD By requesting a test that follows the principles of TDD (Test-Driven Development), you indicate that you are interested in a development approach that prioritizes code quality and continuous validation. This directs the response to include best practices and testing frameworks that align with this methodology.

  4. Request Structure The structure of your request is logical and organized. You asked for a specific test for a functionality, which is an efficient practice in TDD. This helps to avoid overly general answers and allows the response to provide a practical and applicable example.

  5. Clear Expectations By specifying that you want an integration test, you make it clear that you expect an example that not only checks the isolated functionality but also tests the interaction between components, which is fundamental in complex applications.

  6. Use of Technical Terminology The use of terms like "combobox," "autocomplete," and "MUI" demonstrates an understanding of the domain, which allows the response to be more technical and precise, addressing aspects that are relevant to developers familiar with these technologies.

Problems:

  1. In the case of the frontend, since we don't have a database, we don't have the possibility of having something in memory. We need to use a mock or a stub for test environments, yet the AI did not provide either. This is because we asked for an integration test using the TDD philosophy; in this case, we should have specified that we wanted the creation of this mock. This contradicts the backend example used below, which actually needs to mention that it does not want mocks. Perhaps this conflicting behavior is due to the data sources the AI is trained on, where most backend projects follow the wrong practice of mocking everything, while on the front end, developers generally have an idea more aligned with TDD in general.

Java / Spring

Given the feature of adding a manager to a user through an autocomplete combobox followed by a list where the selected ones are placed, give me the integration test for the backend of this feature using Spring Test with MockMvc following the principles of TDD.

Result of this prompt

// UserControllerTest.java
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;

@WebMvcTest(UserController.class)
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Mock
    private UserService userService; // Assuming you have a service for user manipulation

    @InjectMocks
    private UserController userController;

    private ObjectMapper objectMapper;

    @BeforeEach
    public void setup() {
        MockitoAnnotations.openMocks(this);
        objectMapper = new ObjectMapper();
    }

    @Test
    public void shouldAddManagerToUser() throws Exception {
        // Input data
        Long userId = 1L;
        String managerName = "Manager A";

        // Simulating the service's behavior
        when(userService.addManagerToUser(userId, managerName)).thenReturn(true);

        // Executing the request
        mockMvc.perform(post("/api/users/{userId}/managers", userId)
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(managerName)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.message").value("Manager added successfully"));
    }
}

Problems

  1. It used a mock of the user service, which is contrary to the TDD methodology where tests should be decoupled from the implementation. One cannot deduce that a service layer will be used. Furthermore, testing the functionality as a whole would embrace the use of an in-memory database.

  2. It did not create the tests for the manager search endpoint. The failure to mention that this endpoint also needs to be tested, although whether or not this test should be done should be... [sentence seems incomplete in original]

Conclusion

The use of Artificial Intelligence (AI) in software development, especially in practices like Test-Driven Development (TDD), offers a valuable opportunity to optimize and enhance the efficiency of coding and testing processes. As discussed, well-structured prompts that use specific technical terminology are essential for obtaining more accurate and relevant responses from the AI. Technical domain knowledge not only improves the quality of requests made to the AI but also empowers developers to critically evaluate the generated solutions.

However, it is crucial to be aware of the limitations that AI may present, especially regarding the creation of tests that adhere to TDD best practices. Examples such as the need for mocks in a frontend environment or the use of service mocks in backend tests show that AI can sometimes follow patterns that do not perfectly align with development expectations and philosophies. This reinforces the need for solid technical knowledge, which enables the developer to identify and correct any flaws in the responses generated by the AI.