scala spring web mvc - scala

I have a scala controller:
#Controller
#RequestMapping(Array("/welcome"))
class HelloController{
#RequestMapping{val method = Array(RequestMethod.GET)}
def printWelcome(model: ModelMap) = {
println("IN: printWelcome(..)")
val greeting = new GreetingBean("Yo!", "Adam")
model.addAttribute("message", greeting);
"secure" // sends to the /jsf/secure.xhtml page
}
#RequestMapping{val value = Array("/greeting"), val method = Array(RequestMethod.GET)}
def greeting(model: ModelMap) = {
println("IN: greeting(..)")
val greeting = new GreetingBean("Greetings", "Davies")
model.addAttribute("greeting", greeting);
"greeting"; // sends to the /jsf/greeting.xhtml page
}
}
When i call http://localhost:8080/jsf-spring-guice/welcome the message IN: printWelcome(..) is displayed in the console and the correct page is navigated to.
when I call http://localhost:8080/jsf-spring-guice/welcome/greeting I get a 404 error.
I have tried specifying the #RequestMapping on the greetings method in different ways:
#RequestMapping{val value = Array("greeting"), val method = Array(RequestMethod.GET)}
#RequestMapping{val value = Array("/greeting")}
#RequestMapping(Array("/greeting"))
#RequestMapping(Array("/greeting"), Array(RequestMethod.GET))
and de-compiled the generated class which always looks fine. But I always get OK with welcome and always 202 with /welcome/greeting
The decompiled Scala class has this:
#RequestMapping({"/welcome"})
and this:
#RequestMapping(value={"/greeting"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
I can't see any reason why this should not be working. Can anyone help?

Haven't check it and compile, but #RequestMapping annotation for printWelcome method should also have specified value, even if it is empty ("").
The specified value acts as a filter and that's likely the cause of the problem.

Solved
...But couldn't find the answer on Spring documentation.
Situation was I had in web.xml
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/welcome/*</url-pattern>
</servlet-mapping>
This meant that the mapping '#RequestMapping(Array("/welcome"))' had no effect and any request to http://localhost:8080/jsf-spring-guice/welcome would be processed by method marked with #RequestMapping{val method = Array(RequestMethod.GET)}. A kind of default get.
The clue was that when I entered http://localhost:8080/jsf-spring-guice/welcome/welcome/greeting/ the method marked with #RequestMapping{val value = Array("/greeting"), val method = Array(RequestMethod.GET)} was called. At this point it was clear that the double welcome meant something was amiss.
So basically, the url-pattern acts as a pre-fix to URL patters (we all know that), but the catch is that the controller with a simple GET method will act as a default.
Note to self do not use controller with same request mapping as url-pattern

Related

Mocking Httpcalls always return NullPointerException

I'm trying to mock Http calls for unit test.
To do that I have done the following, I have created a RequestMock case class:
case class RequestMock() {
def sendRequest(httpRequest: HttpRequest)(implicit actorSystem: ActorSystem): Future[HttpResponse] = {
Http().singleRequest(httpRequest)
}
}
and in my service, I have written the following piece of code :
case class Service(requestHandler: RequestMock) {
....
for {
response <- {
requestHandler.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000"
)
)
} yield {
response
}
}
For the unit test, I'm trying to mock HttpCalls, to do that, I have done the following :
def test_2 = mock[RequestMock]
And for defining the mock behaviour I have done the following
when(test_2.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000")
)).thenReturn{
Future(
HttpResponse(
StatusCodes.OK,
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`,"connection established"))
But, when I execute unit tests, I always get the following error:
java.lang.NullPointerException
Does anyone know how I can solve this issue ?
A couple of problems.
First of all, test_2 should be a val, not a def.
With def like you have it, you get a different instance every time you access it. So, you define the stub on one instance, but then create your Service with a different one, that does not have sendRequest defined, so returns null by default, and that causes your NPE.
The next problem, that you will probably encounter after you fix this one is that you are not defining all of the behavior.
when(test_2.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000")
))
Only creates a stub for a method call with this specific parameter value. So, if your tests try to make a POST for example or hit a different endpoint, you'll get an NPE again.
Even if you only ever use one request, it is better to define the stub for any argument, to avoid weird NPE failures if the code happens to send a different one (you are writing a test, so should not just assume automatically, that the code will always do what you expect - you would not need the test in the first place if that was the case):
when(test2.sendRequest(any)),thenReturn(Future.successful(...))
(Note Future.successful above – that's the correct way to create Future that is immediately satisfied, what you are doing makes it run on a thread ... not a big deal in your case, but still icky).
Then, after the test code is run, you can check that the parameter value passed to the sendRequest was actually what you expect:
verify(test2)
.sendRequest(HttpRequest(method = HttpMethods.GET, uri = "http://database:9000"))

Play Framework request attributes with typed key

I seem to have issues accessing the attributes of the request attributes map in Play. Following the explanation offered by Play (Link), I should get the correct data from the attributes, but the Option is returned as None.
My structure is as follows. One controller (later injected named as "sec") has the typed attribute for shared access to it:
val AuthenticatedAsAttr: TypedKey[AuthenticatedEmail] = TypedKey("AuthenticatedAs")
The type AuthenticatedEmail is defined in the companion object of this controller as a case class:
case class AuthenticatedEmail(email: String)
The filter passes the attribute to the next request:
val attrs = requestHeader.attrs + TypedEntry[AuthenticatedEmail](sec.AuthenticatedAsAttr, AuthenticatedEmail(email))
nextFilter(requestHeader.withAttrs(attrs))
When trying to then access this attribute in another controller, the returned Option is None:
val auth = request.attrs.get(sec.AuthenticatedAsAttr)
I confirmed via println that the value is definitely in request.attrs but run out of options to debug the issue successfully. A fraction of the println output below.
(Request attrs,{HandlerDef -> HandlerDef(sun.misc .... ,POST, ... Cookies -> Container<Cookies(Cookie ... , AuthenticatedAs -> AuthenticatedEmail(a#test.de), ... })
My Scala version is 2.12.6, Play Framework version 2.6.18. Any help is highly appreciated.
It turns out that the TypedKey must be within an object, not an inject-able controller. So moving it to an object like the following resolves the issue:
object Attrs {
val AuthenticatedAsAttr: TypedKey[AuthenticatedEmail] = TypedKey("AuthenticatedAs")
}
The reason is the implementation of TypedKey (Link), which does not contain an equals method and therefore reverts to comparing memory references.

Dynamics CRM - Unit Testing a plugin with RhinoMocks give weird result

I am writing a unit test for a plugin using Dynamics CRM with RhinoMocks.
After stubbing out the OrganizationService.Retrieve() method, when I invoke the stubbed out method, I am getting null back.
From what I can see (correct me if I'm wrong), is that the stubbed out method signature must the same as the invocation signature.
Here is my code:
TestSetup
var someGuid = Guid.Empty;
var organisationServiceMock = MockRepository.GenerateMock<IOrganizationService>();
organisationServiceMock.Expect(x => x.Retrieve("someCrmEntity", someGuid, SomeCrmEntityColumnSetQuery.ColumnSet))
.Return(new Entity
{
LogicalName = "someCrmEntity",
Id = Guid.NewGuid(),
});
SomeCrmEntityColumnSetQuery Code
public static class SomeCrmEntityColumnSetQuery
{
public static ColumnSet ColumnSet => new ColumnSet("column1", "column2");
}
Invocation Code
var someEntity = organisationServiceMock.Retrieve("someCrmEntity", someGuid, SomeCrmEntityColumnSetQuery.ColumnSet);
//someEntity is null
Things I have tried
Removed the ColumnSet and replaced it with null - this works
Replaced the static class SomeCrmEntityColumnSetQuery with a default instance (new ColumnSet())
I have set the someGuid to Guid.Empty thinking that it was not "joining" on the correct Guid hence the null return value.
I have tried to replace .Expect() with .Stub() - no joy
Edit
In the expectation, I have tried the .WhenCalled(...) and that is how I found out that if I replace the columnSet argument with a null in the expectation and the invocation, it works. So it's go to do with something in my static class that represents a ColumnSet. The code works as I have it running in my DEV environment.
If anyone can share some light on this, that would be magic!
Charles
So I found the answer after watching a PluralSight video on RhinoMocks.
My problem was that when setting up the stub, the stub does not take values but rather the signature of the method that you are stubbing out. For e.g:
var organisationServiceMock = MockRepository.GenerateMock();
//Wrong
organisationServiceMock.Expect(x => x.Retrieve("someCrmEntity", someGuid, SomeCrmEntityColumnSetQuery.ColumnSet)).Return(new Entity());
//The stub does not care about what values are being sent into the method when invoked but rather if the method signature types match.
//Correct
organisationServiceMock.Expect(x => x.Retrieve(Arg.Is.Anything, Arg.Is.Anything, Arg.Is.Anything)).Return(new Entity());
//During the invocation, stubbed method now expects the first argument to be a string, then 2nd to be a Guid, 3rd to be a ColumnSet.
I hope this helps anyone who has also been struggling with this. :)

How to execute tests on the argument that a controller passes to the view in Play Framework

In our play application every controller function fetches data from the database (or some other way) and passes these values to the result
def index = Action { implicit request =>
val newsItems: List[String] = fetchNewsFromDB()
Ok(views.html.home.index(newsItems))
}
def fetchNewsFromDB() = List("Headline1", "Headline2")
I am writing tests using specifiactions (based on the documentation http://www.playframework.com/documentation/2.2.x/ScalaTest)
According to this documentation by controller as follows. In the next test I want to make sure that the index page contains a headline. I do this by checking if there exists a div with the class "headline"
"Example Page#index" should {
"should contain a headline" in {
val controller = new TestController()
val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
val bodyText: String = contentAsString(result)
bodyText.toLowerCase must contain("<div class=\"headline\"")
}
}
However I would rather check whether the list newsItems which the controller passes to the view is nonempty.
What is the best way to do this?
Is it possible to this in a generic way for which little modification of the controllers is required?
I too was frustrated that I couldn't intercept the parameters on their way to the template - and in fact it can become extremely difficult to even get the template to render at all in tests if you have a lot of "state" in your pages (for example, implicits that provide the user object, navigation helpers etc).
What I ended up doing was putting in an extra "seam" for testability in my controllers; in my tests, I extend the controller under test, replacing the HTML rendering function with a mocked one, which I can then use to verify the parameters.
Here's a simple example based on your "news" Action; first, the controller, which is no longer an object so we can extend it:
object Application extends ApplicationController
trait ApplicationController extends Controller {
def newsAction = Action {
Ok(renderNews("this is the news"))
}
def renderNews(s:List[String]):Html = html.sandbox(s)
}
The renderNews method gives us the all-important "test seam". I think it also actually improves the readability of controller methods too, which is nice :-)
Now, the unit test:
class ApplicationSpec extends Specification with Mockito {
val mockedNewsRenderer = mock[List[String] => Html]
val controller = new ApplicationController {
override def renderNews(s:List[String]) = mockedNewsRenderer(s)
}
"Application News Controller" should {
"Pass a non-empty list of news items to the template" in {
val result = controller.newsAction(FakeRequest())
status(result) must beEqualTo(200)
val captor = ArgumentCaptor.forClass(classOf[List[String]])
there was one(mockedNewsRenderer).apply(captor.capture())
val theArgument = captor.getValue
theArgument.isEmpty must beFalse
}
}
}
We create a mock to stand-in for the renderNews function, extend the controller so that we can substitute it in (note that we don't change anything else about it of course), and then call the action as normal. Note that we still get a standard Play Result so we can still check status codes etc, but then, we can use the Mockito verify functionality that's built into Specs2, together with Mockito's ArgumentCaptor facility to assert that our template was indeed called, and that it was supplied with a non-empty list of strings.
This approach has worked well for me - it makes it possible to get really good code coverage of your controllers with fast-running and easy-to-write unit tests.
You have a very good question and a very valid point on testing controllers, but I'm afraid it can't be done easily. The problem is that the views compile to Scala functions meaning when you call views.html.home.index(newsItems) it will return an object of Html, which already has the Html put together and compiled. If you would like to test what get's passed in you need to intercept it before the view is called.
To solve this you would have to rewrite your controllers, by moving all your business logic out of the controller and only have the necessary request handling code there. That would almost be easier to test.

How to get rid of the __actions__ entry in the CrudRestController's response?

I'm subclassing the CrudRestController to implement an REST interface. It works fine, but the response dict contains an __actions__ entry which contains some html code that I really don't want in my response.
According to the TableFiller class' docstring something like this should work:
class ProcessController(CrudRestController):
model = Process
#...
class table_filler_type(TableFiller):
__model__ = Process
__actions__ = False
But the page always throws an AttributeError: 'Process' object has no attribute '__actions__'
Any advice?
Despite the inline docs, the correct way seems to be:
class table_filler_type(TableFiller):
__model__ = Process
__omit_fields__ = ['__actions__', ]