For whatever reason Mocktio will not mock a method I have in a trait, it will call the actual method. Here is my test:
"displays the index page" in {
val mockAuth = mock[AuthMethods]
when(mockAuth.isAllowed(-1, "", "")).thenReturn(true)
val controller = new TestController()
val result = controller.index().apply(FakeRequest())
val bodyText = contentAsString(result)
bodyText must include ("Name")
}
Here is the trait and object:
trait AuthMethods {
def isAllowed(userID:Long, method:String, controller:String) : Boolean = {
//do stuff..
}
object Authorized extends AuthMethods with ActionBuilder [Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
if(isAllowed(userID, method, controller) {
//do some more stuff..
}
Any thoughts on why its calling the actual method verses the mocked method? I am using Scala 2.10.4. Any help would be appreciated.
I forgot to mention, Authorized is a Action Composition and here is how it is being used:
def index = Authorized {
Ok(html.Stations.index(Stations.retrieveAllStations))
}
You have created a mock implementation mockAuth but have not done anything with it. Creating a mock implementation will not magically cause it to replace some other object. It looks like you want to create a mock of the Authorized object and arrange for your TestController to use it. You'll probably have to break a dependency somewhere.
(updated) Since this is in the context of the Play framework, you might find this blog post helpful. It describes a situation similar to yours. It appears you will have to change the way the Authorized object is referenced in order to supply a mock implementation.
Related
I am trying to test
trait Name extends Helper {
def name() = {
var s = getSystem()
s.name()
}
}
where all I want to do is make sure that the "s.name()" method is invoked once by mocking an instance of s, which is a System.
Helper is defined as so:
trait Helper {
def getSystem() : System = {
systemGetter.get()
}
}
As of now, my NameSpec looks something like:
class NameSpec extends FlatSpec with Matchers with MockitoSugar {
class NameImpl extends Name
var toTest = new NameImpl
val mockSystem = mock[System]
it should "call s.name() once" in {
when(getSystem() is invoked, return a mockSystem)
toTest.name()
// Verify that mockSystem.name() happened only once
}
}
What I'm confused about is how to return a mock System in toTest.name() when it calls getSystem() so that I can verify that the system calls s.name() only once. I could easily mock this System if it were a parameter to the name() method in Name trait, so I guess I don't know how to "inject" a mockSystem to be used instead of a real system when that method is invoked.
Unfortunately your code is not compilable and thus is obviously an inadequate representation of what you really have. Particularly it is not clear how the Helper really gets an object of type System. I think that in the real code you should mock the systemGetter, that I suppose is somehow injected into the objects implementing Helper trait, to return your mockSystem. However it is hard to show you a valid example of that basing on the code you provided. If for some reason this is not what you can do, there are a few more avenues.
You seem to use something like Cake pattern around Helper and its inheritance. If so, you can use a class instead of NameImpl to inject System:
class NameWithInjectedSystem(val system: System) extends Name {
override def getSystem(): System = system
}
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = new NameWithInjectedSystem(mockSystem)
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should === (mockName)
verify(mockSystem, times(1)).name()
}
Finally you can mock even nameToTest object itself but this is not the way I'd suggest because it binds test to much more implementation details than you should want:
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = mock[NameImpl]
when(nameToTest.getSystem()).thenReturn(mockSystem)
when(nameToTest.name()).thenCallRealMethod()
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should ===(mockName)
verify(mockSystem, times(1)).name()
}
Note how you must call thenCallRealMethod for the .name() call and so you should do for all the calls inside the name or the test will not work.
I'm developing a scala Web application with play framework, the first time i used filter in order to validate the request but i had no result then i tried to use action builder i had to override 2 methods here is my ActionBuilder Object
object MyJsonAction extends ActionBuilder[Request, Response] with Results {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
println (request.body)// returning null everytime why ?
block(request)
}
override def parser = { // what does this method do, i think the problem started from here :/ ?
null;
}
override protected def executionContext = {
null;
}
}
Well, there are no much resource with play framework just simple examples and there is no example briefly explain what those methods are doing, they tell that you can get request body without telling you how ! everything is ambiguous ! im stuck with it since 3 days a go, and i have no idea what should i do now. thanks
An ActionBuilder is an object that build an Action. An Action combines a BodyParser[T], which reads the request body and constructs a T, with a function Request[T] => Future[Result] to process the T.
The default ActionBuilder does this in a very simple way. It chains together the BodyParser's result and feeds it to the function. If you make a custom ActionBuilder then you can override this process, perhaps by injecting your own logic before or after the function call.
If you're making your own ActionBuilder I'd suggest starting with something like the following as a template:
#Singleton
class MyJsonAction #Inject() (
bodyParsers: PlayBodyParsers,
ec: ExecutionContext) extends ActionBuilder[Request, JsValue] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
println(request.body) // DO SOMETHING HERE
block(request)
}
override def parser = bodyParsers.json
override protected def executionContext = ec
}
Then you can use it in your controllers like this:
class MyController #Inject() (myJsonAction: MyJsonAction) {
def index = myJsonAction { req: Request[JsValue] => ??? }
}
The important piece is the parser: BodyParser[A] it takes the incoming bytes and convert them into a type A.
For instance BodyParser[JsValue] will produce a body of type JsValue. It is used to read Json.
If you are trying to validate an object, maybe an action builder is not the right place to start. You may focus more on the BodyParsers and the json validation
I'm using Play! 2.4 with Deadbolt2 for authorization. However, since I introduced the authorization rules, I'm unable to write successful tests for my controllers. As an example:
class VisitController #Inject() (authorization: DeadboltActions) extends Controller {
def fetchDailyVisits(date: Date) = authorization.Restrict(List(Array(ADMIN_ROLE), Array(MANAGER_ROLE))) {
Action.async {
visitService.findDailyVisits(date).map(result =>
Ok(Json.toJson(result))
)
}
}
}
I'm using specs2 in the tests. My test looks like this atm:
class VisitControllerSpec extends PlaySpecification with Mockito with ScalaFutures {
val deadboltActions = mock[DeadboltActions]
"VisitControllerSpec#fetchDailyVisits" should {
val testDate = Date.from(LocalDate.of(2016, 2, 25)
.atStartOfDay(ZoneId.systemDefault()).toInstant)
"Return Status Ok with returned list" in {
val expected = List(completeVisitWithId, anotherCompleteVisitWithId)
visitService.findDailyVisits(testDate) returns Future { expected }
val request = FakeRequest(GET, "/visits?date=2016-02-25")
val result = new VisitController(deadboltActions)
.fetchDailyVisits(testDate)(request)
result.futureValue.header.status must beEqualTo(OK)
contentAsJson(result) must_== Json.toJson(expected)
}
}
}
How do I mock deadboltActions in a way I can specify the user will be allowed access?
Is there another way? Maybe by providing a different DeadboltHandler? It seems kind of obvious this would be the way to go, I just don't seem to be able to figure it out and there aren't a lot of Deadbolt2 examples out there (at least for scala).
Or, being more extreme, any other authorization framework out there that works well with scala play and allows to handle security as a cross-cutting concern without poluting the controllers? Deadbolt2 is too limited for this reason, but I honestly can't find a better authorization framework (unless I write my own).
There are a number of different ways you can do this.
If your DeadboltHandler has a DAO injected for accessing the subject, you can override the binding of the DAO to provide one containing test subjects.
abstract class AbstractControllerSpec extends PlaySpecification {
sequential
isolated
def testApp: Application = new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()
}
See the test app for an example of using this approach.
Alternatively, you can extend your DeadboltHandler implementation to override getSubject and provide a test subject from here. The binding is handled in the same way as above.
Finally, you can keep all your code as-is and populate the test database with subjects; the requests you send will be shaped by your authentication requirements (headers, something in a cookie, etc).
For unit testing, something similar applies. Given a SubjectDao that has some hard-coded subjects for test purposes, you can use WithApplication and an injector look-up to get what you need.
class TestSubjectDao extends SubjectDao {
val subjects: Map[String, Subject] = Map("greet" -> new SecuritySubject("greet",
List(SecurityRole("foo"),
SecurityRole("bar")),
List(SecurityPermission("killer.undead.zombie"))),
"lotte" -> new SecuritySubject("lotte",
List(SecurityRole("hurdy")),
List(SecurityPermission("killer.undead.vampire"))),
"steve" -> new SecuritySubject("steve",
List(SecurityRole("bar")),
List(SecurityPermission("curator.museum.insects"))),
"mani" -> new SecuritySubject("mani",
List(SecurityRole("bar"),
SecurityRole("hurdy")),
List(SecurityPermission("zombie.movie.enthusiast"))),
"trippel" -> new SecuritySubject("trippel",
List(SecurityRole("foo"),
SecurityRole("hurdy")),
List[SecurityPermission]()))
override def user(userName: String): Option[Subject] = subjects.get(userName)
}
With a controller that looks something like this:
class Subject #Inject()(deadbolt: DeadboltActions) extends Controller {
def subjectMustBePresent = deadbolt.SubjectPresent()() { authRequest =>
Future {
Ok("Content accessible")
}
}
}
We can then unit test it like this:
import be.objectify.deadbolt.scala.DeadboltActions
import be.objectify.deadbolt.scala.test.controllers.composed.Subject
import be.objectify.deadbolt.scala.test.dao.{SubjectDao, TestSubjectDao}
import play.api.Mode
import play.api.inject._
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.mvc.{Result, Results}
import play.api.test.{FakeRequest, PlaySpecification, WithApplication}
import scala.concurrent.Future
object SubjectPresentUnitSpec extends PlaySpecification with Results {
"Subject present " should {
"should result in a 401 when no subject is present" in new WithApplication(new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()) {
val deadbolt: DeadboltActions = implicitApp.injector.instanceOf[DeadboltActions]
val controller = new Subject(deadbolt)
val result: Future[Result] = call(controller.subjectMustBePresent(), FakeRequest())
val statusCode: Int = status(result)
statusCode must be equalTo 401
}
"should result in a 200 when a subject is present" in new WithApplication(new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()) {
val deadbolt: DeadboltActions = implicitApp.injector.instanceOf[DeadboltActions]
val controller = new Subject(deadbolt)
val result: Future[Result] = call(controller.subjectMustBePresent(), FakeRequest().withHeaders(("x-deadbolt-test-user", "greet")))
val statusCode: Int = status(result)
statusCode must be equalTo 200
}
}
}
It doesn't answer exactly to my original question, which was mostly related with Deadbolt2, but I kept getting frustrated with the fact I had to specify my authorization rules in my controllers, which is not truly cross cutting.
The answer provided by Steve Chaloner helps, but still forced me to go through a few hoops.
Enter Panoptes. This authorization framework is based on Filters instead of Action chaining, so it allows to easily specify authorization rules in a central location and outside of the controllers.
Setting your security rules in Panoptes is somewhat similar to Spring Security and it looks like this:
class BasicAuthHandler extends AuthorizationHandler {
override def config: Set[(Pattern, _ <: AuthorizationRule)] = {
Set(
Pattern(Some(POST), "/products") -> atLeastOne(withRole("Admin"), withRole("Manager"))
Pattern(Some(GET), "/cart[/A-Za-z0-9]*") -> withRole("Admin"),
Pattern(None, "/orders[/A-Za-z0-9]*") -> withRole("Admin")
)
}
}
Other than that, you need a couple of lines to declare the filter and plug in your AuthorizationHandler.
class Filters #Inject()(securityFilter: SecurityFilter) extends HttpFilters {
override def filters = Seq(securityFilter)
}
class ControllerProviderModule extends AbstractModule {
override def configure(): Unit = { bind(classOf[AuthorizationHandler]).to(classOf[MyAuthorizationHandler])
}
}
The README file in the git repository has more details and code samples.
It's also customizable to the point it allows to create your own AuthorizationRules. In my project I have a requirement where I need to check the mobile device that makes the call is registered in the system. I can write an AuthorizationRule to handle this for me for every request whose path matches my pattern.
Unit testing controllers is extra simple, because any mocking of the security layer can be ommited. They can be tested like any other class.
If you're having similar issues or also believe authorization rules don't belong in the controllers, have a go at Panoptes, it might suit your needs. Hope this helps someone else.
Combining an ActionBuilder that transforms a request into a custom WrappedRequest with an additional type parameter, and then combining that with an ActionFilter causes the type of the custom WrappedRequest to be dropped.
Why is this and is there a fix?
For example, lets say I need to an authentication ActionBuilder and an optional, authorisation ActionFilter where the user type we need can vary depending on use.
See this contrived code:
case class AuthRequest[A, U](val request: Request[A], val user: U) extends WrappedRequest[A](request)
case class TestUser(id: String)
case class AuthenticationAction[A]() extends ActionBuilder[({type λ[B] = AuthRequest[B, TestUser]})#λ] {
override def invokeBlock[A](request: Request[A], block: (AuthRequest[A, TestUser]) => Future[Result]): Future[Result] =
block(AuthRequest(request, TestUser("test-id")))
}
case class AuthorisedAction[A]() extends ActionFilter[({type λ[B] = AuthRequest[B, TestUser]})#λ] {
// does some additional authorisation checks for added security
def authorised(user: TestUser) = true
override def filter[A](request: AuthRequest[A, TestUser]) = Future.successful {
if( authorised(request.user) ) None
else Some(Unauthorized)
}
}
Please note: The type function in the above is required as per this answer because of the additional type parameter on the AuthRequest. Again this is required because this API will be used with more than one type of user.
If I then implement a controller that uses the above:
class ExampleController extends Controller {
def secured = (AuthenticationAction() andThen AuthorisedAction()) { request =>
Ok(request.user.id)
}
}
I get a compiler error (value user is not a member of play.api.mvc.WrappedRequest[play.api.mvc.AnyContent]). In other words, the type of the variable request above is WrappedRequest instead of the expected type of AuthRequest[play.api.mvc.AnyContent, TestUser]!
I understand that most use cases the AuthenticationAction and AuthorisedAction would be combined into a single action but, because authorisation is optional, I would like to keep these as separate concerns.
Is this possible? Is this a bug in the Play Framework API? Or a Scala bug? Or human error?
Using your example I was able to compose the actions like this:
class ExampleController extends Controller {
def secured = AuthorisedAction().compose(AuthenticationAction()) { request =>
Ok(request.user.id)
}
}
It's interesting to note that in both cases IntelliJ's type inspection sees request as being of type AuthRequest[AnyContent, TestUser] -- it's only scalac that sees it as a WrappedRequest.
Background
I am trying to understand best practices for bringing implicit objects into scope within a Scala application.
I have a Playframework 2.2.0 (Scala 2.10) web app that mixes in a trait for Authorization. It checks. The Authenticated object checks that there is a user_id in scope, attempts to retrieve the user info, access token, and a data package object called a MagicNotebook from cache, database, and web service call. If the request is valid, then various objects are added to the wrapped request.
object Authenticated extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A],
block: (AuthenticatedRequest[A] => Future[SimpleResult])) = {
request.session.get(userName).map { implicit userId =>
Cache.getAs[DbUser](userKey).map { user =>
Cache.getAs[String](accessTokenKey).map { accessToken =>
Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
block(AuthenticatedRequest(user, accessToken, notebook, request) )
}.getOrElse(startOver)
}.getOrElse {
requestNewAccessToken(user.token).flatMap { response =>
persistAccessToken(response).map { accessToken =>
Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
block(AuthenticatedRequest(user, accessToken, notebook, request))
}.getOrElse(startOver)
}.getOrElse(startOver)
}
}
}.getOrElse(startOver) // user not found in Cache
}.getOrElse(startOver) // userName not found in session
}
}
}
case class AuthenticatedRequest[A](user: DbUser,
accessToken: String,
magic: MagicNotebook,
request: Request[A])
extends WrappedRequest[A](request)
Question
What is the best way to bring these implicit variables into scope?
Through an implicit class?
I tried to use an implicit companion class, with the following code:
object Helper {
implicit class Magical(request: AuthenticatedRequest[AnyContent]) {
def folderMap = request.magic.fMap
def documentMap = request.magic.dMap
}
}
However, I don't really get the benefit of an implicit this way:
def testing = Authenticated { implicit request =>
import services.Helper._
request.magic.home.folders // doesn't compile
request.magic.home.folders(Magical(request).ffMap) // compiles, but not implicitly
Ok("testing 123")
}
Through an import statement?
One possibility I considered was through an import statement within the controller. Here, the request has a MagicNotebook object in scope that I would like to use as an implicit variable.
def testing = Authenticated { implicit request =>
import request.magic._
request.magic.home.folders // implicit map is a parameter to the `folder` method
Ok("testing 123")
}
Through a companion trait?
Here, I create a companion trait that is mixed into the Authenticate trait that includes the two maps of the MagicNotebook object into scope of the controller.
trait Magic {
implicit def folderMap[A](implicit request: AuthenticatedRequest[A]) =
request.magic.fMap
implicit def docMap[A](implicit request: AuthenticatedRequest[A]) =
request.magic.dMap
}
My preference is the companion trait solution, but I was wondering if there might be a better way that I overlooked. I ended up re-writing methods that use the implicit variable, to use the MagicNotebook's two maps instead of whole object as implicit parameters.
But again, I was wondering if there might be a better way.
I am quite partial to package objects for this sort of thing. See What's New in Scala 2.8: Package Objects for a description. Package objects effectively allow you to put implicit classes into a package, which you can't otherwise do.
However, the main snag with this approach is that you can't split the definition of an object across multiple source files, so because the implicit classes need to be defined within the package object, they also need to be all in the same source file. If you have many implicit classes you wish to have imported, this can result in a large and unwieldy source file. However, that in itself is a sign that you have a “package god object” which should be split.
One of the ways I know of defining implicits is by using Package Objects.
package implicitIdiomatic {
implicit def nullableLongToOption(l:java.lang.Long) = Option(l)
}
}
package implicitIdiomatic
class ImplicitIdiomaticTest{
val l:Long = 1
longOpt(l)
def longOpt(l:Option[Long]) = l match {case Some(l1) => println(l1); case None => println("No long")}
}
Kind of useless example but hope you get the idea. Now when longOpt gets l, it is converted to Option[Long] using the implicit.
As long as you are working in the same package as defined by the package object you don't need the import statement.