motoライブラリを使ってAWSリソースのテストをしようとしていたら、突然ImportError: cannot import name 'mock_s3' from 'moto'が出てしまい、ハマった。特にmotoをバージョン4.0.0以降に上げてから、この問題に遭遇するケースが増えたようだ。ローカル環境でのテストが止まってしまうと地味にストレスが溜まる。
何が起きたか(課題)
-
from moto import mock_s3という書き方でテストコードを書いていた。 -
motoを最新版にアップグレードした後、テスト実行時にインポートエラーが発生するようになった。 - これは、以前のようにルートパッケージから直接モックをインポートできなくなったことが原因だった。
- 結果として、AWS連携部分の単体テストや結合テストが実行できず、開発がストップしていた。
どう解決したか(概要)
このエラーの根本原因は、motoバージョン4.0.0以降で導入されたパッケージ構造の変更にある。以前は全てのモックがルートパッケージに集約されていたが、現在はサービスごとにモジュールが分離された。解決策は、この新しい構造に合わせてインポートパスを修正することと、必要なエクストラ依存関係をインストールすることの二点だ。
まず、インポート文を以下のように修正した。
古いインポート(動作しない):
from moto import mock_s3
新しい正しいインポート:
from moto.s3 import mock_s3
他のサービス(DynamoDBやEC2など)も同様に、moto.dynamodbやmoto.ec2といったサービス固有のパスからインポートする必要がある。また、モックしたいサービスに対応するエクストラパッケージをインストールすることも重要だ。例えばS3とDynamoDBをモックするなら、pip install "moto[s3,dynamodb]"を実行した。
効果(Before/After)
| 項目 | Before(エラー発生時) | After(修正後) |
|---|---|---|
| テスト実行 | 失敗(ImportError) | 成功(モック環境が即座に立ち上がる) |
| 開発フロー | テスト修正のために時間を浪費 | 依存関係の解決が明確になりスムーズに進行 |
| コードの可読性 | ルートインポートで曖昧だった | サービス固有のパス指定で意図が明確になった |
この修正により、AWSリソースを伴うテストコードが以前と同じように動作するようになり、CI/CDパイプラインでのテスト実行も安定した。作業時間は約15分程度で済んだ。
🚀 詳細な設定とコードはこちら
具体的なS3モックを用いたpytestフィクスチャの例や、バージョン確認コマンドの詳細は元のブログで公開しています。