🥦

Django-DRFでFileField(ImageField)のユニットテストどうするのか

2022/09/21に公開

始めに

Django、DjangoRestFrameworkを使用したAPI開発後、ファイルアップロード(POST, PUT)をどのように実装するのか、以外とハマったので備忘兼共有
※コードベースで行います

環境

django==3.2.x
djangorestframework==3.13.1

ViewでParserを設定

file_upload_api_view.py

class FileUploadAPIView(APIView):
    
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]
    
    def get_parsers(self):
        """Parserをメソッド毎等条件で切り替える
	PUTのみ[MultipartParser, FormParser]を使用
	"""
	
	self.parser_classes = [JSONParser]
        if self.request.method.upper() == 'PUT':
            self.parser_classes = [MultiPartParser, FormParser]
        return super(UserCurrentProfileAPIView, self).get_parsers()
	
    def put(self, request):
        """PUTメソッド"""
	
        user = self.request.user
	serializer = FileUploadSerializer(data=request.data)
	
	if serializer.is_valid():
		serializer.save()
		return Response(status=200, data=serializer.data)
	else:
	    raise ValidationException("適当に例外をraise")
	

テストコード

test_file_upload_api_view.py
from django.test import TestCase
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from rest_framework.test import APIClient

class FileUploadAPIViewTest(TestCase):
    
    def test_file_upload(self):
      """ファイルアップロードを検証"""
      
      // 準備(ユーザ等の準備処理は割愛)
      api_client = APIClient()
      api_client.credentials(HTTP_AUTHORIZATION=f"Token {token}")
      // パラメータ準備(parameterはimageとnameのみ)
      parameters = {
          "name": "file_name",
          "image": open((os.path.dirname(os.path.abspath(__file__))) + '/sample.jpg', 'rb')
      }
      
      // 実行
      response = api_client.put(
          path="/api/image/upload/",
          data=encode_multipart(data=parameters, boundary=BOUNDARY), 
          content_type=MULTIPART_CONTENT)
      
      // 検証
      self.assertEqual(200, response.status_code)

ひとこと

今回はMultiPartParserを使用したアップロードです。
テストの時に形式関連でエラーが出たりと色々ハマりそうだったので共有です。
実際はファイルをサーバ経由でストレージにアップロードするのも効率が悪いので、直接ストレージにアップロードさせる方が良いと感じてます。(S3署名付きアップロードとか...)

検証内容についてはDB更新されていることの検証等を実行前、実行後に行なったりすると良いと思います。
事前準備は担保されているものとするなら実行後検証のみでOK

さいごに

そういえば今度Djangoのカンファレンスがあるので参加します。一般枠です。
オフラインなので緊張しますが、、、猛者に囲まれて頑張ります。

参考ツイート(今見たら残り1人でした・・・)
https://twitter.com/django_ja/status/1572017039400931331?s=20&t=iaDC8S6qx2B2OoL30zs11w

Discussion