Sobes.tech
Junior

What is a mock in testing?

sobes.tech AI

Answer from AI

Mock — is a stub object that fully imitates the behavior of a real dependent component or service in a testing environment. It allows controlling the return values of dependency methods and checking how the tested code interacts with them.

Main differences from other test stubs (Stubs, Fakes):

  • Stub: Provides predefined responses to method calls but does not verify interaction.
  • Fake: Has a working but simplified implementation of a dependent component.
  • Mock: Mimics behavior, provides predefined responses, and most importantly, allows verifying how the tested code interacted with this object (e.g., which methods were called, how many times, with what arguments).

Purposes:

  • Isolating the tested code from external dependencies (databases, external services, file systems, etc.).
  • Accelerating test execution.
  • Testing boundary cases and error handling, which are difficult to reproduce with real dependencies.
  • Verifying expected interactions between objects.

Example of usage with Mockito:

// Interface to be mocked
public interface UserService {
    User findUserById(long userId);
}

// Class that uses UserService and will be tested
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public String getUserName(long userId) {
        User user = userService.findUserById(userId);
        if (user != null) {
            return user.getName();
        }
        return "User not found";
    }
}

// Test class using mocks
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

public class UserControllerTest {

    @Test
    void getUserName_UserFound() {
        // Create a mock of UserService
        UserService mockUserService = mock(UserService.class);

        // Define mock behavior: when findUserById(1) is called, return a User
        User mockUser = new User(1, "John Doe");
        when(mockUserService.findUserById(1)).thenReturn(mockUser);

        // Create the object under test, passing the mock
        UserController userController = new UserController(mockUserService);

        // Call the method under test
        String userName = userController.getUserName(1);

        // Assert the result
        assertEquals("John Doe", userName);

        // Verify that findUserById was called once with argument 1
        verify(mockUserService, times(1)).findUserById(1);
    }

    @Test
    void getUserName_UserNotFound() {
        UserService mockUserService = mock(UserService.class);

        // Define mock behavior: when findUserById(any long), return null
        when(mockUserService.findUserById(anyLong())).thenReturn(null);

        UserController userController = new UserController(mockUserService);

        String userName = userController.getUserName(2);

        assertEquals("User not found", userName);

        // Verify that findUserById was called once
        verify(mockUserService, times(1)).findUserById(anyLong());
    }

    // Helper class for the example
    static class User {
        private final long id;
        private final String name;

        public User(long id, String name) {
            this.id = id;
            this.name = name;
        }

        public long getId() { return id; }
        public String getName() { return name; }
    }
}