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"))
Related
I've got an akka-http application that uses akka-streams for data processing. So, it makes some sense to complete the request with Source[Result, _] to get backpressure across HTTP boundary for free.
Versions:
akka-http 10.0.7
akka-streams 2.5.2
akka 2.5.2
This is the simplified version of the code, and it works just fine.
pathEnd { post { entity(asSourceOf[Request]) { _ =>
complete {
Source.single("ok")
}
}}}
Since this enpoint is supposed to create and entity, instead of returning 200 OK to the requester I'd like to return 204 CREATED status code. However, I wasn't able to find a way to do that:
complete { Created -> source.single("ok") } fails compilation with Type mismatch, expected: ToResponseMarshallable, actual: (StatusCodes.Success, Source[String, NotUsed])
complete { source.single((Created, "ok")) } fails with Type mismatch, expected: ToResponseMarshallable, actual: Source[(StatusCodes.Success, String), NotUsed]
complete(Created) { Source.single("ok") } fails with Type mismatch, expected: RequestContext, actual: Source[String,NotUsed]
complete(Created, Source.signle("ok") fails with too many arguments for method complete(m: => ToResponseMarshallable)
It looks like custom marshaller might be a way to achieve that, but it'll basically mean I'll need one unmarshaller per endpoint, which isn't quite convenient or clear.
So, the question is, are there a (more convenient than custom unmarshaller) way to complete the request with Source[_,_] while also providing status code.
From the documentation:
complete(Created -> "bar")
If you want to provide some Source of data then construct the HttpResponse and pass it to complete:
import akka.http.scaladsl.model.HttpEntity.Chunked
import akka.http.scaladsl.model.ContentTypes
import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart
complete {
val entity =
Chunked(ContentTypes.`text/plain(UTF-8)`,
Source.single("ok").map(ChunkStreamPart.apply))
HttpResponse(status = Created, entity=entity)
}
I hit this problem and took the approach of using mapResponse to override the status code. This is the simplest approach I've found.
mapResponse(_.copy(status = StatusCodes.Accepted)) {
complete {
Source.single("ok")
}
}
The drawback of Ramon's answer is that you become responsible for both marshalling the stream (to a ByteString), and for the content negotiation.
I have a requirement, I have a method, which takes another function. I want to get the result of this parameter function in my caller.
I have created a code snippet for this scenario:
class ProcessHandler {
def executeInstructions(x:String=>Array[String])
{
//print the resultant list here
}
}
object ProcessHandlerMain {
def main(args: Array[String]) {
val handler = new ProcessHandler
handler.executeInstructions( instruction)
}
def instruction(x:String):Array[String] =
{
List("words", "from", "book").toArray
}
}
This call handler.executeInstructions( instruction) will be made by another process. Here I am using main method to test it out.
Here is what I do not know:
How can I print the result of parameter function
If I have to expose this method executeInstructions() to client side, what is the best approach? Here we will not be passing text instructions, rather a function similar to instruction().
Thanks
Updated: From the response received, my code is updated to
class ProcessHandler {
def executeInstructions(x:String=>Array[String])
{
//print the resultant list here
val result = x("some string here")
//this array will be sent to another service
// dispatcher.dispatch(result)
}
}
My requirements are updated:
How can I print the result of parameter function : Done
If I have to expose this method executeInstructions() to client side, what is the best approach? Here we will not be passing text instructions, rather a function similar to instruction(). Pending
The client interface has will work as below:
1. client will be calling executeInstructions() remotely and pass function as parameter.
2. InstructionId will be passed to the injected function, the resultant array will be dispatched to another service.
I ma writing unit testcases using NUnit and Fake it Easy for MVC4 Controllers.
In one of the controller, I should be getting exception.
ExceptionDetail exception = new ExceptionDetail() { Description = "Test", ErrorCode = ExceptionErrorCode.UserIsDisabled };
Exception ex = new Exception(new Uri("http://localhost//Plat/ManagementSvc/Groups?UserID=" + iD "), exception );
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, url)).Throws(ex);
My question is instead of passing localhost(new Uri("http://localhost//Plat/ManagementSvc/Groups"), is there a way to fake the url for URI
If the problem is that the exception isn't being thrown when your production code calls GetDataAsync, it could just be that your code is passing in a different Uri. If this is so, you can change which Uri triggers that call by using a different form of argument constraint.
Instead of matching the Uri exactly, you could choose to match any Uri:
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, A<Uri>.Ignored))
.Throws(ex);
Or you could even be more specific:
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, A<Uri>.That.Matches(uri => uri.AbsolutePath == "/Plat/ManagementSvc/Groups"))
.Throws(ex);
if that's what's needed. There are many options. Check out the documentation.
Note that there's no faking of a Uri here. You're just telling FakeItEasy what tests to apply to a received Uri in order to decide whether the faked GetDataAsync method should throw
My code looks like:
case class SRecord(trialId: String, private var _max:Int) {
def max=_max
def max_=(value:Int):Unit=_max=value
}
Then later on I apply a function onto it:
def groupSummaryRecords(it:Iterator[Option[SRecord]], optionSummary:Option[SRecord]):Option[SRecord] = {
var max=0;
var sRecord1 : Option[SRecord] = None
var i=0
while(it.hasNext) {
var sRecord:Option[SRecord] = it.next();
if(i==0) {
sRecord1 = sRecord;
}
..
}
sRecord1.max=max; // getting 'reassignment to val' compilation error
..
}
Why am i getting this compilation error, and how to fix it ?
If I instead change sRecord and sRecord1 instances to be of type SRecord instead of Option[SRecord] as well as the method signature, it all works fine however.
But in some cases I may have a null SRecord hence the use of None/Some. I am new to Scala, using Option/Some all over feels like a real pain if you ask me, i am just thinking of removing all this Option nonsense and testing for 'null' in good ol' Java, at least my code would work ??!
With the line sRecord1.max=max you are trying to call the max method on an Option[SRecord], not an SRecord. You want to access the contained SRecord (if any) and call the method on that, which can be done using foreach:
sRecord1.foreach(_.max=max)
which is desugared to:
sRecord1.foreach( srec => srec.max=max )
(the actual name "srec" is made up, the compiler will assign some internal name, but you get the idea). If sRecord1 is None, this won't do anything, but if it is Some(srec), the method execution will be passed in to operate on the contained instance.
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