2014-01-26 45 views
4

我試圖發明某種模擬的SecureSocial動作生成器,或者SecureSocial本身能夠單元測試控制器方法。我發現了一些方法,如Unit-testing methods secured with Securesocial annotationTesting a Play2 application with SecureSocial using dependency injection,但問題是,在這個問題中,作者實際上並不進行單元測試,而是進行集成測試。PlayS框架中的單元測試控制器與SecureSocial

我的單元測試是這樣的:

trait MockDaoProvider extends IDaoProvider { 
    def entityDao = entityDaoMock 
    } 

    val controller = new MyController with MockDaoProvider 

    "MyController.list" should { 
    "return an OK" in { 
     entityDaoMock.list().returns(List()) 

     val result = controller.list()(FakeRequest()) 

     status(result) must equalTo(OK) 
    } 
    } 

正如人們所看到的,我嘲笑的依賴隔離和測試控制器的方法實際執行的行爲。

一切都還好,直到我從securesocial的SecureControlAction使用MyController.list方法。現在我收到一個異常,測試失敗。我不知道如何從securesocial中模擬,存根或覆蓋SecuredAction和UserAwareAction對象。我仍然不想將測試轉換爲路由(...)測試。它們僅用於測試控制器的行爲。

有人遇到同樣的問題?可能有什麼提示如何解決?

PS:玩框架2.2.1,securesocial - 2.1.2

回答

3

它看起來像代碼真的沒有強調可測性,這迫使用戶拿出自己的全新解決方案的作者。 This one用戶機Jeantil可能會有所幫助:

class FakeAuthenticatorStore(app:Application) extends AuthenticatorStore(app) { 
    var authenticator:Option[Authenticator] = None 
    def save(authenticator: Authenticator): Either[Error, Unit] = { 
    this.authenticator=Some(authenticator) 
    Right() 
    } 
    def find(id: String): Either[Error, Option[Authenticator]] = { 
    Some(authenticator.filter(_.id == id)).toRight(new Error("no such authenticator")) 
    } 
    def delete(id: String): Either[Error, Unit] = { 
    this.authenticator=None 
    Right() 
    } 
} 

abstract class WithLoggedUser(val user:User,override val app: FakeApplication = FakeApplication()) extends WithApplication(app) with Mockito{ 
    lazy val mockUserService=mock[UserService] 
    val identity=IdentityUser(Defaults.googleId, user) 

    import helpers._ 
    import TestUsers._ 
    def cookie=Authenticator.create(identity) match { 
    case Right(authenticator) => authenticator.toCookie 
    } 

    override def around[T: AsResult](t: =>T): execute.Result = super.around { 
    mockUserService.find(Defaults.googleId) returns Some(identity) 
    UserService.setService(mockUserService) 
    t 
    } 
} 

    val excludedPlugins=List(
    ,"service.login.MongoUserService" 
    ,"securesocial.core.DefaultAuthenticatorStore" 
) 
    val includedPlugins = List(
    "helpers.FakeAuthenticatorStore" 
) 

    def minimalApp = FakeApplication(withGlobal =minimalGlobal, withoutPlugins=excludedPlugins,additionalPlugins = includedPlugins) 

然後允許測試這樣

"create a new user password " in new WithLoggedUser(socialUser,minimalApp) { 
    val controller = new TestController 
    val req: Request[AnyContent] = FakeRequest(). 
    withHeaders((HeaderNames.CONTENT_TYPE, "application/x-www-form-urlencoded")). 
    withCookies(cookie) // Fake cookie from the WithloggedUser trait 

    val requestBody = Enumerator("password=foobarkix".getBytes) andThen Enumerator.eof 
    val result = requestBody |>>> controller.create.apply(req) 

    val actual: Int= status(result) 
    actual must be equalTo 201 
} 
+0

我不能說更好:) – Jean

+0

我只是希望我做你正義哈哈。 – Vidya

1

經過一番思考,探索和實驗,我結束了一個優雅的解決方案。該解決方案依賴於依賴注入的「蛋糕模式」。就像這樣:

守則控制器:

trait AbstractSecurity { 
    def Secured(action: SecuredRequest[AnyContent] => Result): Action[AnyContent] 
} 

trait SecureSocialSecurity extends AbstractSecurity with securesocial.core.SecureSocial { 
    def Secured(action: SecuredRequest[AnyContent] => Result): Action[AnyContent] = SecuredAction { action } 
} 

abstract class MyController extends Controller with AbstractSecurity { 

    def entityDao: IEntityDao 

    def list = Secured { request => 
    Ok(
     JsArray(entityDao.list()) 
    ) 
    } 
} 

object MyController extends MyController with PsqlDaoProvider with SecureSocialSecurity 

和測試代碼:

trait MockedSecurity extends AbstractSecurity { 
    val user = Account(NotAssigned, IdentityId("test", "userpass"), "Test", "User", 
     "Test user", Some("[email protected]"), AuthenticationMethod("userPassword")) 

    def Secured(action: SecuredRequest[AnyContent] => play.api.mvc.Result): Action[AnyContent] = Action { request => 
     action(new SecuredRequest(user, request)) 
    } 
    } 


    val controller = new MyController with MockDaoProvider with MockedSecurity 

    "IssueController.list" should { 
    "return an OK" in { 
     entityDaoMock.list().returns(List()) 

     val result = controller.list()(FakeRequest()) 

     status(result) must equalTo(OK) 
    } 
    } 

還有一個缺點 - 測試取決於securesocial類以及...但是...這真的是一個缺點嗎? 我不知道這種方法在更復雜的情況下如何工作,我們會看到。