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
}
}