概要
前回は、mock-alchemyを使ってテストコードを書いてみました。 今回は、SQLiteを使った場合のテストコードを書いてみようと思います。
やりたいこと
今回のテストも、レポジトリ層の関数に対してのテストとなります。ただ前回と違い、今回はデータベース(SQLite)を使用するので、「データベースがどうなったか」を確認することが出来ます。そこを活かして、今回のテスト内容は以下のイメージです。
- レポジトリ層の関数を呼び出した時、データベースに対して意図した操作(INSERT、SELECT、UPDATE、DELETEなど)が行われ、データベースが意図したように変化したか。
- データベース操作の結果が返ってきた時、その結果に基づいて、関数の戻り値が想定通りの内容になっているか。
これらを、Create(作成)、Read(読み取り)、Update(更新)、Delete(削除)の各操作で確認していきます。
事前準備
テスト対象のコードは、前回と同じプログラムです。
前回はこちら
- models.py
- repository.py
やってみた
それでは、実際にテストコードを書いていきます。 テストコード用として下記を用意しました。
- test_sqlite_repository.py
import pytest from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from models import Base, User from repository import UserRepository from unittest.mock import MagicMock @pytest.fixture def session(): engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) TestingSessionLocal = sessionmaker(bind=engine) db = TestingSessionLocal() yield db db.close() @pytest.fixture def repo(session): return UserRepository(session) def test_create_user(): pass def test_get_user(): pass def test_update_user(): pass def test_delete_user(): pass
CREATE
まずはCreate。
テスト内容としては、
- 関数に対して登録したい値を渡した時、データベースに登録されたか。
- 関数の戻り値として、登録された結果が呼び出し元に返されるか。
となります。
実際に書いてみたのがこちら。
def test_create_user(repo): # given: name = "Taro" email = "taro@example.com" # when: ユーザーを作成する user = repo.create(name=name, email=email) # then: ユーザーが正しく作成されていることを確認する assert user.id is not None assert user.name == name assert user.email == email
実際の登録処理を動かし、その結果が想定通りか確認しています。
READ
次はRead。
テスト内容としては、
- 関数に対して取得したい値(条件)を渡した時、データベースの値を取得したか。
- 関数の戻り値として、取得された結果が呼び出し元に返されるか。
となります。
実際に書いてみたのがこちら。
def test_get_user(repo): # given: 既存のユーザーを作成する user = repo.create(name="Jiro", email="jiro@example.com") # when: ユーザーIDでユーザーを取得する found = repo.get(user.id) # then: ユーザーが正しく取得できることを確認する assert found is not None assert found.name == "Jiro"
初めに登録処理でデータを登録し、そのあとに取得処理を動かすことで、結果が想定通りか確認します。
UPDATE
次はUpdate。
テスト内容としては、
- 関数に対して更新したい値を渡した時、データベースの値を更新したか。
- 関数の戻り値として、更新された結果が呼び出し元に返されるか。
となります。
実際に書いてみたのがこちら。
def test_update_user(repo): # given: 既存のユーザーを作成する user = repo.create(name="Saburo", email="saburo@example.com") # when: ユーザー情報を更新する updated = repo.update(user.id, name="SaburoUpdated", email="saburo2@example.com") # then: ユーザー情報が正しく更新されていることを確認する assert updated.name == "SaburoUpdated" assert updated.email == "saburo2@example.com"
こちらも初めに登録処理でデータを登録し、そのあとに更新処理を動かすことで、戻り値が想定通りか確認します。
DELETE
次はDelete。
テスト内容としては、
- 関数に対して削除したい値(条件)を渡した時、データベースのデータを削除したか。
- 関数の戻り値として、削除された結果が呼び出し元に返されるか。
となります。
実際に書いてみたのがこちら。
def test_delete_user(repo): # given: 既存のユーザーを作成する user = repo.create(name="Shiro", email="shiro@example.com") # when: ユーザーを削除する result = repo.delete(user.id) # then: ユーザーが削除され、取得できないことを確認する assert result is True assert repo.get(user.id) is None
こちらも初めに登録処理でデータを登録し、そのあとに削除処理を動かします。
戻り値の確認と、最初に登録したデータを取得してデータがないことを確認しています。
まとめ
前回に比べて、かなり記述量が少なくテストを書くことが出来ました。これは、実際のデータベースを使用することで得られる大きな利点ですね。
ただ、取得、更新、削除のテストでデータ作成の処理を使っているので、作成のロジックがエラーとなったときは、すべてのテストがエラーとなりますね(笑
まぁでも、問題なく動きの確認もできますし、次にテストコードを書く機会があれば、SQLiteを使って書こうと思いました。