Playframework2.6でファイルアップロードのユニットテスト

Multipartでファイルアップロードするapiのテストを行いたかったんだけど、めちゃくちゃハマったというか、わからなかったのでここにメモする!

ポイント1 「アップロードするファイルをリソースから取得する」

まず、テストケースで使用するリソース(今回はアップロードするファイル)はどこに保存すればいいのか分からんね!

そんな時は次のコマンドを叩けばわかるぞ!

sbt "show test:resourceDirectory" 
> [info] Test / resourceDirectory
> [info] /Users/honyarara/project/test/resources

そしてこのファイルを取得するにはこうだ!

/Users/honyarara/project/test/resources/testfile.jpg を取得する時は。

val fileUrl = getClass.getResource("/testfile.jpg")

先頭のスラッシュが無いとnullになっちゃうので注意!

 

ポイント2 「multipart/form-dataのFakeRequestを作成する」

WEBに転がってる情報が古くて正解になかなかたどり着けなかったよ。

最初に リソースから取得したファイルをTemporaryFileに変換する。 既に存在するファイルのTemporaryFileって何言ってるんだ?と思うかもしれないが、そういうもんだ。

val tempFile = SingletonTemporaryFileCreator.create(Paths.get(fileUrl.toURI))

で、このtempFileを使ってFilePartを作成する

val filepart = FilePart[TemporaryFile]("imageFile","testfile.jpg",Some("image/jpeg"),tempFile)

次にファイルと同時に送信するフォーム情報を作成する

val data:Map[String,Seq[String]] = Map(
  "title" -> Seq("パイスラッシュ女子")
)

後は、ここまでの情報を組み立てればOK

val formData = MultipartFormData[TemporaryFile](
	dataParts = data,files = Seq(filepart),badParts = Seq())

val request = FakeRequest(POST,"/upload")
	.withMultipartFormDataBody(formData);	

これで “multipart/form-data” なFakeRequestができる。

 

ポイント3 「実行する!」

実行時にはroute経由でやらないと上手く動かなかった。

val result = route(app, request).get
status(result) mustBe OK

 

まとめると

import java.nio.file.Paths
import play.api.libs.Files.SingletonTemporaryFileCreator
import play.api.libs.Files.TemporaryFile
import play.api.mvc.MultipartFormData
import play.api.mvc.MultipartFormData.FilePart

class UploadControllerSpec extends PlaySpec with GuiceOneAppPerTest with Injecting
{
  "画像をuploadするとOkを返すよ" in {

  	// 送信するフォームデータ
	val data:Map[String,Seq[String]] = Map(
	  "title" -> Seq("パイスラッシュ女子大生")
	)

	// リソースからファイルを取得してTemporaryFileを作成する
  	val fileUrl = getClass.getResource("/testfile.jpg")
  	val tempFile = SingletonTemporaryFileCreator.create(Paths.get(fileUrl.toURI))

  	// ファイルパートを作成する
  	val filepart = FilePart[TemporaryFile](
  			"imageFile","testfile.jpg",Some("image/jpeg"),tempFile)

  	// 組み合わせてMultipartFormDataを作成
  	val formData = MultipartFormData[TemporaryFile](
  		dataParts = data,files = Seq(filepart),badParts = Seq())

  	// FakeRequestを作成
  	val request = FakeRequest(POST,uploadEndpointUrl)
  		.withMultipartFormDataBody(formData)

  	// 実行
  	val result = route(app, request).get
  	status(result) mustBe OK
  }
}