


| 요소 | 모키시스트(Mockist) | 클래시스트(Classicist) | 
|---|---|---|
| 테스트 중점 | 행동 | 상태 | 
| 테스트 포커스 | 상호 작용 | 결과 | 
| 모킹 사용 | 네 | 아니요 | 
| 테스트 복잡성 | 낮음 | 높음 | 
| 외부 의존성 | 낮음 | 높음 | 
public class UserRegisterController {
    private final RegisterUserUseCase registerUserUseCase;
    private final UserResponseMapper userResponseMapper;
    @PostMapping("/register")
    public ResponseEntity<T> registerUser(
            @RequestBody RegisterUserRequest registerUserRequest
    ) {
        RegisterUserCommand command = RegisterUserCommand.builder()
                .username(registerUserRequest.getUsername())
                // 등등
                .build();
        User user = registerUserUseCase.registerUser(command);
        RegisterUserResponse response = userResponseMapper.mapToRegisterUserResponse(user);
        
				return ResponseEntity.status(HttpStatus.OK).body(response);
    }
}@ExtendWith(MockitoExtension.class)
@DisplayName("UserRegisterController 단위 테스트")
public class UserRegisterControllerTest {
    @Mock
    private RegisterUserUseCase registerUserUseCase;
    @Mock
    private UserResponseMapper userResponseMapper;
    @InjectMocks
    private UserRegisterController userRegisterController;
    RegisterUserRequest request;
    User mockUser;
    RegisterUserResponse mockResponse;
    @BeforeEach
    public void setUp() {
        // RegisterUserRequest 객체 생성
        request = new RegisterUserRequest(
                "testuser",
                // 등등(필요에 따라 추가)
        );
        // User 객체 생성
        mockUser = User.builder()
                .userId(1L)
								// 등등(필요에 따라 추가)
                .build();
        // RegisterUserResponse 객체 생성
        mockResponse = RegisterUserResponse.builder()
                .username("testuser")
								// 등등(필요에 따라 추가)
                .build();
    }
		// 밑에서 이어짐
}UserRegisterControllerTest코드가 너무 길어 두 분류로 나눠서 설명을 하겠다.@ExtendWith(MockitoExtension.class) → 해당 범위에서 Mockito의 기능을 사용할 수 있게 해준다.RegisterUserUseCase, UserResponseMapper → 이 두 부분은 UserRegisterController에서 의존성으로 @Mock을 등록하여 실제 객체를 만드는 것이 아닌 가짜 객체를 만들어 등록을 해주기 위함이다.UserRegisterController → @InjectMocks을 위에서 등록한 두 Mock 객체를 사용할 수 있도록 설정해둔다.RegisterUserUseCase, UserResponseMapper)를 직접 구현하지 않아도 되고 UserRegisterController에 로직만 명확하게 테스트가 가능하다.@BeforeEach → 모든 테스트가 실행 되기 전에 먼저 실행 되는 메소드이다.@ExtendWith(MockitoExtension.class)
@DisplayName("UserRegisterController 단위 테스트")
public class UserRegisterControllerTest {
    @Test
    @DisplayName("회원가입 요청에 대한 성공 응답 반환")
    public void shouldRegisterUser() throws Exception {
        // given
        when(registerUserUseCase.registerUser(any())).thenReturn(mockUser);
        when(userResponseMapper.mapToRegisterUserResponse(any())).thenReturn(mockResponse);
        // when
        ResponseEntity<ReturnObject> response = userRegisterController.registerUser(request);
        // then
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertEquals(mockResponse, response.getBody().getData());
        verify(registerUserUseCase, times(1)).registerUser(any());
        verify(userResponseMapper, times(1)).mapToRegisterUserResponse(any());
    }
}shouldRegisterUser)에 대한 테스트 코드를 보겠다.when(registerUserUseCase.registerUser(any())).thenReturn(mockUser) → 의존성으로 주입 받은 registerUserUseCase클래스에 registerUser 메소드에 아무 값(any())이 들어가도 그 결과 값은 꼭 mockUser나오게 미리 가정을 해두는 것이다.when(userResponseMapper.mapToRegisterUserResponse(any())).thenReturn(mockResponse) → 의존성으로 주입 받은 userResponseMapper클래스에 mapToRegisterUserResponse메소드에 아무 값(any())이 들어가도 그 결과 값은 꼭 mockResponse나오게 미리 가정을 해두는 것이다.userRegisterController.registerUser(request) → 우린 위에서 @BeforeEach를 통해 request를 미리 만들어두어 바로 사용이 가능하다.assertEquals(HttpStatus.OK, response.getStatusCode()) → 응답 상태 코드가 OK(200)인지 확인한다.assertEquals(mockResponse, response.getBody().getData()) → 응답 본문의 데이터가 우리가 mocking한 response 객체와 동일한지 확인한다.verify(registerUserUseCase, times(1)).registerUser(any()) → UserRegisterController에서 registerUserUseCase.registerUser()가 1번 실행됐는지 확인하기.verify(userResponseMapper, times(1)).mapToRegisterUserResponse(any()) → UserRegisterController에서 userResponseMapper.mapToRegisterUserResponse()가 1번 실행됐는지 확인하기.@DisplayName("UserRegisterController 단위 테스트")
public class UserRegisterControllerTest {
    private UserRegisterController userRegisterController;
    private RegisterUserUseCase registerUserUseCaseFake;
    private UserResponseMapper userResponseMapperFake;
    @BeforeEach
    void setUp() {
        registerUserUseCaseFake = new RegisterUserUseCaseFake();
        userResponseMapperFake = new UserResponseMapperFake();
        userRegisterController = new UserRegisterController(registerUserUseCaseFake, userResponseMapperFake);
    }
    private static class RegisterUserUseCaseFake implements RegisterUserUseCase {
        @Override
        public User registerUser(RegisterUserCommand command) {
            return User.builder()
                    .username(command.getUsername())
                    .build();
        }
    }
    private static class UserResponseMapperFake extends UserResponseMapper {
        @Override
        public RegisterUserResponse mapToRegisterUserResponse(User user) {
            return RegisterUserResponse.builder()
                    .username(user.getUsername())
                    .build();
        }
        // UserRegisterController에서는 사용하지 않는 메소드라 구현 X
        @Override
        public LoginUserResponse mapToLoginUserResponse(User user) {
            return null;
        }
    }
}UserRegisterControllerTest코드가 너무 길어 두 분류로 나눠서 설명을 하겠다.RegisterUserUseCase, UserResponseMapper)에 대한 구현체(RegisterUserUseCaseFake, UserResponseMapperFake)를 만들어주어야한다.@BeforeEach → UserRegisterController에 대한 의존성(Fake)을 생성자로 초기화 시켜준다.class RegisterUserUseCaseFake implements RegisterUserUseCase → RegisterUserUseCase 인터페이스의 registerUser 메소드를 오버라이딩한다.class UserResponseMapperFake extends UserResponseMapper → UserResponseMapper 인터페이스의 mapToRegisterUserResponse, mapToLoginUserResponse메소드를 오버라이딩하고 구현한다.UserRegisterController클래스에서 mapToLoginUserResponse를 사용하지 않기에 디테일하게 구현하지 않았다.@DisplayName("UserRegisterController 단위 테스트")
public class UserRegisterControllerTest {
    
		@Test
    @DisplayName("회원가입 요청에 대한 성공 응답 반환")
    void testRegisterUserSuccess() {
				// given
        RegisterUserRequest request = new RegisterUserRequest(
                "testuser123",
                "Test@12345",
                "Test@12345",
                "testNickname",
                "010-1234-5678",
                "test@example.com"
        );
				// when
        ResponseEntity<ReturnObject> responseEntity = userRegisterController.registerUser(request);
        // then
        assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        assertNotNull(responseEntity.getBody());
        assertEquals(request.getUsername(), ((RegisterUserResponse) responseEntity.getBody().getData()).getUsername());
    }
}testRegisterUserSuccess) 메소드에 대한 테스트 코드를 보겠다.UserRegisterController에서 registerUser메소드에 들어가는 request를 정의해준다.assertEquals(HttpStatus.OK, responseEntity.getStatusCode()) → 실제 값에서 200ok가 나왔는지 확인한다.assertNotNull(responseEntity.getBody()) → 실제 값이 있는지 판단한다.assertEquals(request.getUsername(), ((RegisterUserResponse) responseEntity.getBody().getData()).getUsername()) → request로 받은 유저 네임과 실제 반환된 값에 유저 네임이 같은지 확인한다.UserRegisterController)를 테스트를 하려니 모키시스트는 의존성에 대한 클래스를 Mocking 해주면 편하게 작업하였지만, 클래시스트는 의존성에 대한 클래스를 일일이 다 구현해줘야해서 생각보다 오래걸렸다.