1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Play2のstackable-controllerを使ってみる

Posted at

概要

(play2-authの前準備としての記事になります)

stackable-controllerとは、Play2で認証系を担うplay2-authを裏で支えているライブラリです。

(ちなみに、僕は他でどう使えるのかはよくわかってないです。。logging処理を挟みたいならfilterでいけそうですし、DBのトランザクション管理はService層でDIで解決出来そうなので。)

環境

  • Play2.5
  • stackable-controller 0.6.0

Elementを用意する

まずはStackの対象とするElementを作っていきます。
ここでは、1/2の確率でlong値を生成して返すという処理を書いてみます。

MyStackLongElement.scala
import akka.actor.ActorSystem
import jp.t2v.lab.play2.stackc.{RequestAttributeKey, RequestWithAttributes, StackableController}
import play.api.mvc.{Controller, Result}

import scala.concurrent.Future
import scala.util.Random

trait MyStackLongElement extends StackableController {
  self: Controller =>

  val actorSystem: ActorSystem
  val random: Random

  private case object LongKey extends RequestAttributeKey[Long]

  override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result] = {
    implicit val ctx = actorSystem.dispatcher
    val long = random.nextLong()
    val isFail = random.nextBoolean()
    if(isFail) return Future{ BadRequest }

    super.proceed(req.set(LongKey, long))(f)
  }

  def getStackedLong()(implicit req: RequestWithAttributes[_]): Long = req.get(LongKey).get
}

このElementは、proceedの中でreq.set(LongKey, long)をしています。
なんらかの処理結果をここでsetしているわけですね。
(ちなみに、条件が合わない場合はそのままBadRequestなどのResultを返すこともできます。)

値をsetしたことによって、このElementを実装したcontrollerの中では、getStackedLongを通じてreq.get(LongKey).getを行い値を取得することが出来るようになります。

Controllerを実装する

StackController.scala
import javax.inject.{Inject, Singleton}

import akka.actor.ActorSystem
import play.api.mvc.Controller

import scala.concurrent.{ExecutionContext, Future}
import scala.util.Random

@Singleton
class StackController @Inject() (
  override val actorSystem: ActorSystem,
  override val random:Random = new Random
) extends Controller with MyStackLongElement {

  implicit val myExecutionContext: ExecutionContext = actorSystem.dispatcher

  def message = AsyncStack { implicit req =>
    Future{
      val long = getStackedLong()
      Ok(long.toString)
    }
  }
}

先ほど用意したMyStackLongElementをextendsして、任意の場所でgetStackedLongを呼ぶだけです。
(なお、ここではRandomはテストしやすいようにDIする形にしました。)

stackable-controllerの役割はこれでほぼ全部と認識しています。
cleanupOnSucceeded あたりはfilterに吸収されそう。。。。)

テストを書く

stackable-controllerを用いていても、普通のControllerと同じようにテストを行えます。

StackControllerTest.scala
import java.util.concurrent.TimeUnit

import akka.actor.ActorSystem
import akka.util.Timeout
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import org.scalatest.{FunSpec, MustMatchers}
import play.api.mvc.Result
import play.api.test.{FakeRequest, Helpers}

import scala.concurrent.Future
import scala.util.Random

class StackControllerTest extends FunSpec with MustMatchers with MockitoSugar  {

  describe("StackControllerTest") {

    implicit val timeout = Timeout(5000, TimeUnit.MILLISECONDS)

    it("StackController success"){
      val randomMock = mock[Random]
      when(randomMock.nextLong()) thenReturn 100L
      when(randomMock.nextBoolean()) thenReturn false
      val actorSystem = ActorSystem.apply()
      val controller = new StackController(actorSystem, randomMock)

      val result: Future[Result] = controller.message().apply(FakeRequest())
      Helpers.contentAsString(result) mustBe "100"
      Helpers.status(result) mustBe 200
    }

    it("StackController fail"){
      val randomMock = mock[Random]
      when(randomMock.nextLong()) thenReturn 100L
      when(randomMock.nextBoolean()) thenReturn true
      val actorSystem = ActorSystem.apply()
      val controller = new StackController(actorSystem, randomMock)

      val result: Future[Result] = controller.message().apply(FakeRequest())
      Helpers.status(result) mustBe 400
      Helpers.contentAsString(result) mustBe ""
    }
  }
}

MyStackLongElementは、randomで1/2で失敗するように作っています。
なのでテスト時にはMockを使って成功・失敗をコントロールして動作確認してみました。

なるべくグローバルに依存しないように作れば、このようにテストも容易になります。

まとめ

これだけだとあまり嬉しさがわからないと思うので、play2-authの記事を待つべし。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?