Private 를 모킹 해야하나 말아야하나 ?? ,1. { user: { id: mockUser.id } }가 필요한 이유

2024. 11. 29. 22:42·Daily Logs/TIL (Today I Learned)

1. Private 를 모킹 해야하나 말아야하나 ?? 

 

1. 모킹이 필요한 경우

모킹이 필요한 이유

  • 외부 종속성 차단: 테스트 대상 코드가 데이터베이스, API 호출, 파일 시스템 등 외부 시스템에 의존한다면, 이러한 외부 종속성을 차단하여 테스트를 독립적으로 실행할 수 있도록 하기 위해 모킹이 필요합니다.
  • 테스트 속도: 실제 데이터베이스를 호출하거나 HTTP 요청을 보내는 작업은 느리고 불안정할 수 있습니다. 모킹은 이러한 문제를 피할 수 있습니다.
  • 예외 상황 시뮬레이션: 예를 들어, 데이터베이스가 비정상적으로 작동하거나 네트워크 오류가 발생하는 상황을 테스트하려면, 모킹이 필수적입니다.
  • 상태 제어: 모킹을 통해 테스트에 필요한 특정 상태(예: 특정 데이터를 가진 사용자)를 쉽게 설정할 수 있습니다.

2. 모킹이 필요하지 않은 경우

실제 구현을 사용할 수 있는 경우

  • 단순 비즈니스 로직 테스트: 코드가 외부 시스템에 의존하지 않는다면, 실제 구현을 사용하는 테스트로 충분할 수 있습니다.
    • 예: verifyCode처럼 단순히 매개변수 비교를 수행하는 경우.
  • 엔드 투 엔드(E2E) 테스트: 전체 시스템의 동작을 검증하는 E2E 테스트에서는 실제 데이터베이스, API 등을 사용하여 시스템의 전체 흐름을 확인합니다.
    • 이 경우, 모킹은 테스트 목적과 반대되므로 사용하지 않습니다.
private async verifyCode(code: string, req: Request): Promise<boolean> {
  return code === req.session.code;
}
  • 모킹이 필요하지 않은 경우: 단순한 비즈니스 로직(외부 종속성이 없는 경우)을 테스트할 때.
  • 모킹이 필요한 경우: 데이터베이스, 파일 시스템, 외부 API 등 외부 시스템과 상호작용이 있는 경우.

따라서, verifyCode 같은 단순한 로직에서는 모킹이 필수가 아니지만, 복잡한 의존성을 가지는 메서드(예: deleteUserAccount)에서는 모킹이 필요합니다.

2.await this.findChannelByUserId(user.id); 를 where: { user: { id: mockUser.id } },이런식으로 사용해야한다.

async updateVideo(
    user: UserEntity,
    videoId: number,
    updateVideoDto: UpdateVideoDto,
  ): Promise<VideoEntity> {
    await this.findChannelByUserId(user.id);

    const foundVideo = await this.findVideoById(videoId);

    const updateData = await this.updateDetails(updateVideoDto, foundVideo);

    await this.videoRepository.update({ id: videoId }, updateData);

    const updatedVideo = await this.videoRepository.findOne({ where: { id: videoId } });
    return updatedVideo;
  }

 

it('수정된 비디오 메타데이터를 반환한다.', async () => {
      mockChannelRepository.findOne.mockResolvedValue(mockChannel);
      mockVideoRepository.findOne.mockResolvedValue(mockVideo);
      mockVideoRepository.update.mockResolvedValue(undefined);
      mockVideoRepository.findOne.mockResolvedValue(mockUpdatedVideo);

      const result = await videoService.updateVideo(mockUser, 1, mockUpdateVideoDto);

      expect(channelRepository.findOne).toHaveBeenLastCalledWith({
        where: { user: { id: mockUser.id } },
      });
      expect(videoRepository.findOne).toHaveBeenCalledWith({ where: { id: 1 } });
      expect(videoRepository.update).toHaveBeenCalledWith(
        { id: 1 },
        {
          title: mockUpdateVideoDto.title,
          description: mockUpdateVideoDto.description,
          thumbnailUrl: mockUpdateVideoDto.thumbnailUrl,
          hashtags: mockUpdateVideoDto.hashtags,
          visibility: mockUpdateVideoDto.visibility,
        },
      );
      expect(result).toEqual(mockUpdatedVideo);
    });

 

{ user: { id: mockUser.id } }와 (user.id)와 같은 접근 방식의 차이는 데이터베이스 관계와 **ORM(Query)**에서의 동작 방식 때문입니다. 이 차이는 ORM 모델링 구조와 쿼리 빌더 작성 규칙에 따라 달라집니다.

1. { user: { id: mockUser.id } }가 필요한 이유

NestJS에서 TypeORM과 같은 ORM을 사용할 때, 연관 관계가 설정된 엔티티를 조회하거나 필터링하는 경우, 객체 형태로 경로를 지정해야 합니다.

예시: TypeORM 엔티티 관계

@Entity()
export class ChannelEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => UserEntity, (user) => user.channels)
  user: UserEntity; // 관계 필드
}

데이터베이스 구조:

  • ChannelEntity는 UserEntity와 ManyToOne 관계를 가지므로, TypeORM은 내부적으로 userId 필드를 사용해 연결합니다.
  • 하지만 TypeORM 쿼리는 userId를 직접 사용하지 않고, 객체 구조를 통해 관계를 표현합니다.

2. 왜 단순히 (user.id)를 사용하지 않는가?

(user.id)는 관계를 명시적으로 정의하지 않으므로, TypeORM에서 아래 두 가지 문제가 발생할 수 있습니다:

  1. 직접 필드를 참조하려면 명시적 데이터베이스 필드 이름을 사용해야 함
    • TypeORM에서 user.id처럼 관계를 간접적으로 사용하는 경우, ORM은 관계를 제대로 인식하지 못합니다.

3. 언제 (user.id)를 사용할 수 있나?

(user.id)처럼 단순히 userId 필드를 직접 사용하는 경우는 관계 설정이 없는 경우에만 가능합니다. 예를 들어, 아래와 같이 테이블에 직접적인 외래 키(userId)만 존재하고, TypeORM 관계가 설정되지 않은 경우:

@Entity()
export class ChannelEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  userId: number; // 단순 필드로만 존재
}
channelRepository.findOne({
  where: { userId: mockUser.id }, // 가능 (단순 외래 키 필드 접근)
});

하지만 이 방식은 ORM의 장점을 제대로 활용하지 못하고, 관계를 표현하지 못하므로 권장되지 않습니다.

4. 결론

  • ORM 관계가 설정된 경우:
where: { user: { id: mockUser.id } }

직접 필드를 사용하는 경우:

where: { userId: mockUser.id }

'Daily Logs > TIL (Today I Learned)' 카테고리의 다른 글

const로 선언된 변수는 재할당이 불가능하다.  (0) 2024.12.11
숏폼 프로젝트 ES LINT , prettier 설정 및 트러블 슈팅  (0) 2024.12.08
JavaScript deep dive 변수 선언의 실행 시점과 변수 호이스팅  (0) 2024.11.27
스웨거 활용법  (0) 2024.11.08
와이어 프레임의 중요성  (1) 2024.10.21
'Daily Logs/TIL (Today I Learned)' 카테고리의 다른 글
  • const로 선언된 변수는 재할당이 불가능하다.
  • 숏폼 프로젝트 ES LINT , prettier 설정 및 트러블 슈팅
  • JavaScript deep dive 변수 선언의 실행 시점과 변수 호이스팅
  • 스웨거 활용법
Jcob.moon
Jcob.moon
반가워요~ 하루하루 꾸준히 코딩 작성하는 곳입니다 !!
  • Jcob.moon
    Pixelated Thoughts
    Jcob.moon
  • 전체
    오늘
    어제
    • HelloWorld (174)
      • Daily Logs (123)
        • TIL (Today I Learned) (64)
        • Algorithm Practice (55)
        • Dev Book Notes (4)
      • Deep Dives (36)
        • 문제 해결 (Troubleshooting) (3)
        • CS Fundamentals (22)
        • Career Prep (4)
        • Technical Notes (7)
      • Project Log (7)
      • Any (3)
      • Cooperation (4)
        • Github (2)
        • Conventions (1)
        • Git (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
Jcob.moon
Private 를 모킹 해야하나 말아야하나 ?? ,1. { user: { id: mockUser.id } }가 필요한 이유
상단으로

티스토리툴바