만들고자 하는 것
회원 정보를 받아 DB 에 넣기
유효성 검사는 여기서 진행하지 않음.
만들기
model 추가
db/models.py 에 User 모델을 추가한다.
테이블 이름은 user 로 하였으며 저장하는 정보는 다음과 같다.
id 는 따로 설정하지 않고 기본 값으로 uuid 를 사용하도록 하였다.
- id: uuid4 로 생성
 - username: 사용자 이름
 - email: 이메일
 - nickname: 닉네임
 - sign_up_status: 회원가입 상태
 - hashed_password: 비밀번호
 
import uuid
...
class User(Base):
    __tablename__ = "user"
    id = Column(
        String(36),
        default=uuid.uuid4,
        primary_key=True,
        index=True,
        nullable=False,
    )
    username = Column(String(20))
    email = Column(String(30))
    nickname = Column(String(20))
    sign_up_status = Column(String(30))
    hased_password = Column(String(100))
schema 추가
db/schemas.py 에 스키마를 추가한다.
기본적으로 사용자 정보를 사용할 때 쓸 User 를 만들고 회원 가입 시에만 필요한 정보를 추가로 받는 SignUpInDB 를 만든다.
class User(BaseModel):
    username: str
    email: EmailStr
    nickname: str
    sign_up_status: str = 'WAITING_EMAIL_VERIFICATION'
    
class SignUpInDB(User):
    hased_password: str
crud 중 c(create) 추가
db/curd.py 에 create_user 함수를 추가한다.
def create_user(db: Session, user: schemas.SignUpInDB):
    db_user = models.User(
        **user.dict(),
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user
테스트 케이스 작성하기
test_models.py 를 만들고 테스트 케이스를 작성한다.
디비가 필요한 테스트 케이스가 계속해서 생겨날 것이기 때문에 db 를 테스트 케이스마다 작성할 수는 없기에 fixture 를 이용하였다. fixture 를 통해 테스트 케이스에 db 를 넘겨주도록 하였다. fixture 의 범위를 module, class, session 등으로 설정 가능하다. 그 중에서 여기서는 module 로 설정하였다.
import pytest
from faker import Faker
from sqlalchemy.orm import Session
from db import models
from db.crud import create_user
from db.database import engine, SessionLocal
from db.schemas import SignUpRequest, SignUpInDB
@pytest.fixture(scope="module")
def db():
    models.Base.metadata.create_all(bind=engine)
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
fake = Faker()
def test_sign_up(db: Session):
    sign_up_request = SignUpRequest(
        username=fake.user_name(),
        email=fake.email(),
        nickname=fake.name(),
        plain_password=fake.password(),
    )
    sign_up_user = SignUpInDB(**sign_up_request.dict(),
                              hased_password=sign_up_request.hashed_password)
    created_user = create_user(db, sign_up_user)
    # e.g id: 065ae0ac-50d3-4648-81d7-35acd566f16b
    assert len(created_user.id.split('-')) == 5
DB 를 확인해보면 성공적으로 값이 들어왔다.

여기서 문제는 테스트 데이터인데 테스트 데이터는 테스트 케이스가 끝나면 지워져야 한다. 크게 방법은 2가지를 생각해볼 수 있다.
- 테스트 케이스 별로 각자가 만든 데이터는 각자가 지우기
 - 전체 또는 국지적으로 테스트 실행이 종료되면 한 번에 삭제하기
 
1번도 가능하지만 그럼 테스트 케이스마다 중복된 코드가 많아진다. 또한 return 값이 필요없지만 return 을 만들어 사용해야하기도 한다.
그러기에 2번이 대체로 낫다. 그렇다면 한 번에 테스트 데이터를 지우려면 어떻게 지워야 하는가? 테스트 데이터라는 것을 알려주면 된다.
예를 들어 어떤 값에 test- 를 붙이는 것이다.
after & before
테스트가 실행 전(before) 과 후(after) 에 특정한 행동을 하기 위해서는 아래와 같은 fixture 가 필요하다. 이 코드는 test_models.py 에 추가했다.
@pytest.fixture(autouse=True, scope='module')
def run_around_tests():
    print('before')
    yield
    print('after')
위 코드를 추가 후 테스트 케이스를 돌리고 로그를 보면 scope 가 module 이기 때문에 현재 1개만 실행된다. PASSSED 전후에 before 와 after 가 로그가 출력된다.
before
PASSED                                   [  9%]
after
테스트 사용자 삭제 코드 추가
test- 로 시작하는 데이터 삭제하도록 하는 쿼리이다.
crud.py 에 추가하였다.
from sqlalchemy import true
...
def delete_test_user(db: Session):
    db.query(models.User).where(User.username.startswith('test-') == true()).delete()
    db.commit()
다시 test_models.py 로 돌아와 코드를 추가한다.
@pytest.fixture(autouse=True, scope='module')
def run_around_tests(db: Session):
    yield
    delete_test_user(db)
그럼 테스트 실행 후 테스트 데이터가 삭제된 것을 확인해볼 수 있다.
현재 유효성 검사, 이메일 인증 단계 등이 없지만 우선 하나하나 작은 기능을 덧입혀 나가보려한다.