[TIL] Worldcup APIs 리팩토링, jest 테스트

김시원·2023년 5월 8일
0

TIL

목록 보기
17/50
post-custom-banner

Issues encountered

  1. transaction: 어떤 계층에? service? repository?
  2. transaction 두 가지 방법 -> managed로 구현해봄
  3. joi validation failed cases test
  4. tables JOIN하기

What I tried

  1. DB transaction은 3-layered architecture에서 service layer에 들어가는 것이 가장 적합하다. Service layer는 비즈니스 로직을 담당하고, 여러 Repository를 조합하여 데이터를 처리한다. 이 때, DB transaction이 필요한 경우가 많기 때문이다.
  • unmanaged: 사용자가 커밋과 롤백을 직접 작성
  • managed: 에러가 발생했을 때 자동으로 롤백, 성공했을 때 자동으로 커밋
  • {transaction: t} 객체를 넘겨주지 않아도 되는가 => sequelize.transaction()을 사용하여 생성한 managed transaction에서는 명시적으로 트랜잭션 객체를 넘겨줄 필요가 없다. sequelize.transaction()은 자체적으로 트랜잭션 객체를 생성하고, 이를 쿼리에 적용하여 트랜잭션을 관리하기 때문이다.
  1. joi validation 실패 케이스를 구현해보았다. toThrow()를 통해 해당 에러를 반환하는지 확인할 수 있다.
mockRequest.body = {
    title: "타이틀 실패 테스트",
    content: "컨텐트 실패 테스트",
    choices: [],
};

{
    mockRequest.body.title = "";
    expect(() =>
      postWorldcupSchema
        .validate(mockRequest.body)
        .toThrow("월드컵 제목이 비어있습니다.")
    );
}
  1. 1) Users, Worldcups Tables JOIN
getAll = async () => {
    return await this.worldcupsModel.findAll({
      include: [
        {
          model: Users,
          attributes: [],
          required: true,
        },
      ],
      attributes: [
        "worldcup_id",
        "user_id",
        "title",
        "content",
        "play_count",
        "likes",
        [Sequelize.literal("`User`.`nickname`"), "nickname"],
        "createdAt",
        "updatedAt",
      ],
      group: ["Worldcups.worldcup_id"],
      order: [["createdAt", "DESC"]],
    });
  };

[Sequelize.literal("User.nickname"), "nickname"]이 없이 그대로 반환하면 {User: {nickname}} 형태로 반환되기 때문에 이중 객체를 없애기 위해 literal()을 사용해주었다. 리터럴(literal) 문자열을 생성하기 위해 사용됩니다.

2) Users, Worldcups, World Tables JOIN

getOne = async (worldcup_id) => {
    return await this.worldcupsModel.findOne({
      include: [
        {
          model: Worldcup_choices,
          attributes: ["choice_name", "choice_url"],
          required: true,
        },
        {
          model: Users,
          attributes: [],
          required: true,
        },
      ],
      attributes: [
        "worldcup_id",
        "user_id",
        "title",
        "content",
        "play_count",
        "likes",
        [Sequelize.literal("`User`.`nickname`"), "nickname"],
        "createdAt",
        "updatedAt",
      ],
      where: { worldcup_id },
    });
  };

해당 코드를 그대로 반환하면 choice_name과 choice_url이 담긴 object가 맨 첫번째 값만 반환되기 때문에 모든 choices objects들을 반환하려면 map으로 따로 처리를 해주어야 한다.

const worldcup_choices = worldcup.Worldcup_choices.map((choice) => ({
      choice_name: choice.choice_name,
      choice_url: choice.choice_url,
    }));

What I newly learned

What to learn next

  • AWS 모든 것 강의
  • CI/CD
  • Integration Test
  • TDD & DDD
  • Node.js 핵심 키워드 공부
  • Nodemailer
  • Git flow
  • 캐시 & 쿼리 최적화
post-custom-banner

0개의 댓글