Specs2 - Mock objects inside method - scala

I'm writting unit tests and i would like to know if it's possible to mock an object that is instanced inside the method that i'm testing.
Here is an example of a method that i would like to test:
def sendMessageToBroker(message:Message) = {
val soapBody = xmlBody("user", "pass", message.identifier,
message.to, message.message)
val response = new WebServiceUtil().doPost("uri", soapBody.toString(),
"text/xml; charset=utf-8", "action")
response
}
I was wondering if it's possible to do something like:
when call doPost, return new Response(200, 'Success')
Is it possible?
I've tried do it using spy() and mock, but no sucess:
val ws = new WebServiceUtil
val spiedObj = spy(ws)
spiedObj.doPost("uri", xml,
"text/xml; charset=utf-8",
"action") returns new Response(200, "Success")
val xx = messageService.sendMessageToBroker(new Message())
Any ideas on how can i do it?

You could write
val webService = mock[WebServiceUtil]
webService.doPost("uri", xml, "text/xml; charset=utf-8", "action") returns
new Response(200, "Success")
// pass the mock webservice as an argument
sendMessageToBroker(new Message, webService)
The important part is that you need to be able to pass a mock WebServiceUtil to your method being tested! There are many ways to do that. The simplest one is to pass the instance to a constructor method of our "class under test":
class MyClass(webService: WebServiceUtil) {
def sendMessageToBroker(message: Message) = {
// use the webservice
}
}
A more involved method would use Guice and the Inject annotation to pass the service (especially since you tagged the question as a play-framework-2.0 one). You will be interested in following this SOF question then.

Related

Modify contentHeaders of Swagger Codegen methods in kotlin

I'm using swagger codegen for my REST API calls. For authentication purposes i need to send a session-token within the headers of every request. This is currently done, via APIClients' defaultHeaders
open class ApiClient(val baseUrl: String) {
companion object {
...
#JvmStatic
var defaultHeaders: Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))
...
}
}
The way swagger generates the code, these headers can only be modified once.
ApiClient.defaultHeaders += mapOf("Authorization" to userSession!!.idToken.jwtToken)
The problem with this is, that i cannot change the token (e.g. because another user logged in within the application lifetime). Looking deeper into the generated code, before each request is sent, a merge of both defaultHeaders and requestConfig.headers (=contentHeaders) is being made.
inline protected fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> {
...
val headers = defaultHeaders + requestConfig.headers
...
}
The given RequestConfig object comes from every api call. However it is not possible to change these contentHeaders. Also they are empty by default.
fun someAPIRestCall(someParam: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = type
val localVariableQuery: MultiValueMap = mapOf()
val contentHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() // THESE WILL BE MERGED WITH defaultHeaders
val acceptsHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Accept" to "application/json")
val localVariableHeaders: kotlin.collections.MutableMap<kotlin.String,kotlin.String> = mutableMapOf()
localVariableHeaders.putAll(contentHeaders)
localVariableHeaders.putAll(acceptsHeaders)
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"someEndpointURL"),
query = localVariableQuery,
headers = localVariableHeaders // THESE WILL BE MERGED WITH defaultHeaders
)
val response = request<Unit>(
localVariableConfig,
localVariableBody
)
...
}
Is it possible to tell swagger-codegen to include some kind of parameter to the generated method signature to add values to those contentHeaders?
EDIT:
This is the current code-gen call within my gradle build chain
task generateSwagger(type: JavaExec) {
main = "-jar"
args "swagger-codegen-cli-2.4.7.jar", "generate", "-i", "./swagger_core.yml", "-l", "kotlin", "-o", "./tmp/RestApi", "--type-mappings", "number=kotlin.Long"
}
By now, i found a solution, that is more of a hack, but it works.
As i am using gradle to build the app, i introduced a task, that changes the generated swagger code, before it actually compiles.
task editAPISources {
def token = "Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))"
def value = "MutableMap<String, String> = mutableMapOf(ContentType to JsonMediaType, Accept to JsonMediaType)"
def file = new File("./app/tmp/RestApi/src/main/kotlin/io/swagger/client/infrastructure/ApiClient.kt")
def newConfig = file.text.replace(token, value)
file.write newConfig
}
The result is a now changeable header :=
#JvmStatic
var defaultHeaders: MutableMap<String, String> = mutableMapOf(ContentType to JsonMediaType, Accept to JsonMediaType)

How to read query parameters in akka-http?

I know akka-http libraries marshal and unmarshal to class type while processing request.But now, I need to read request-parameters of GET request. I tried parameter() method and It is returning ParamDefAux type but i need those values as strings types
I check for answer at below questions.
How can I parse out get request parameters in spray-routing?
Query parameters for GET requests using Akka HTTP (formally known as Spray)
but can't do what i need.
Please tell me how can i extract query parameters from request. OR How can I extract required value from ParamDefAux
Request URL
http://host:port/path?key=authType&value=Basic345
Get method definition
val propName = parameter("key")
val propValue = parameter("value")
complete(persistanceMgr.deleteSetting(propName,propValue))
My method declarations
def deleteSetting(name:String,value:String): Future[String] = Future{
code...
}
For a request like http://host:port/path?key=authType&value=Basic345 try
path("path") {
get {
parameters('key.as[String], 'value.as[String]) { (key, value) =>
complete {
someFunction(key,value)
}
}
}
}
Even though being less explicit in the code, you can also extract all the query parameters at once from the context. You can use as follows:
// Previous part of the Akka HTTP routes ...
extract(_.request.uri.query()) { params =>
complete {
someFunction(key,value)
}
}
If you wish extract query parameters as one piece
extract(ctx => ctx.request.uri.queryString(charset = Charset.defaultCharset)) { queryParams =>
//useyourMethod()
}

Gatling httpRequest with dynamic method from collection

I want to build a Gatling scenario from a collection of structured data (StructuredDataCollection).
My problem is, that I'm unable to pass in the "method" (as in HTTP method) from an element from the collection into the http call of the actual test.
Here's a code snippet.
def testScenario(duration: Int) = scenario("SO").during(duration) {
exec {
session => {
val test = StructuredDataCollection.next()
val title = test.title
val method = test.method // Not being used, because it does not work like that :(
val endpoint = test.endpoint
val requiredParameters = test.requiredParameters
val code = test.code
session
.set("title", title)
.set("methodFUG", method).set("endpoint", endpoint)
.set("requiredParameters", requiredParameters)
.set("code", code)
}
}
.exec(
http("${title}")
.httpRequest("get", "${endpoint}") // TODO: method can't be passed in as an expression.
.queryParamMap("${requiredParameters}")
.check(status.is("${code}"))
)
}
As you can see, I've hard-coded "get", but I'll need that to be replaced with the actual value from the method property from the current selected item from the collection.
Unfortunately, Gatling's DSL isn't available in all the places where you'd expect it to be, and it's just reading that as a string.
It took me some time to realize, that
http("${title}").httpRequest("${methodFUG}", "${endpoint}") will actually make a HTTP call with the invalid method "${methodFUG}" and not the value from the collection element, which could be "GET", "POST", "PUT", "DELETE", and so on.
httpRequest signature is (method: String, url: Expression[String]), see documentation.
It cannot take an Expression, only a static String.

Play WS API Making nested requests - WSClient

I want to make two HTTP requests(POST) using play2 WSRequest where some information from the first response is send to the second request. I tried to do this in following manner to make sure second request is only triggers after the first one is completed. But I get Type mismatch: cannot convert from F.Promise to F.Promise error
public Promise<Result> executeAPI(String apiName,JsonNode requestBody){
WSRequest pcLoginRequest = ws.url("http://xxxxx.qa.local:8080/mytest/rest/login");
pcLoginRequest.setContentType("application/json");
pcLoginRequest.setHeader("X-x-Password", "xxxxx")
.setHeader("X-x-Username", "xxxxx")
.setHeader("X-x-Content-Type", "application/json");
Promise<Result> myPromise = pcLoginRequest.post("").map(response -> {
ProApiSession.getInstanceOf().setProToeken(response.asJson().get("token").asText());
WSRequest pcrequest = ws.url("http://xxxxx.qa.local:8080/mytest/rest/api/" + apiName);
pcrequest.setContentType("application/json");
pcrequest.setHeader("X-x-Token",ProApiSession.getInstanceOf().getProToeken() )
.setBody(requestBody)
.setHeader("X-x-Content-Type", "application/json");
Promise<Result> myPromise2 = pcLoginRequest.post(requestBody).map(response2 -> {
return Results.ok(response2.asJson());
});
return myPromise;
});
Can someone please suggest how to do nested request using WSRequest in play. (import play.libs.ws.* )
Java 8 type inference errors are bad at the best of times. Since the result of the lambda you're passing to the first map is Promise<Result>, what you're trying to assign to myPromise is Promise<Promise<Result>>. What you actually want to do is replace the map call with flatMap, which is so named because is "flattens" the nested promise to just be a single promise.

HTTP CacheControl with Jersey and json implementation

I want to add the CacheControl intormation to a GET service that use the json binding.
I found that to add the cacheControl to a response the REST service sound like this:
#GET
#Path("cacheheadertest")
#Produces({"*/*"})
def testcache():javax.ws.rs.core.Response {
val rb:Response.ResponseBuilder = javax.ws.rs.core.Response.ok("chached test message")
val cc = new CacheControl()
cc.setMaxAge(60)
cc.setNoCache(false)
rb.cacheControl(cc).build()
}
but I have a REST service that produce json messages and the jersey library transform automaticcally the java object from java to xml/json.
#GET
#Path("jsontestcache")
#Produces(Array(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML))
def myjsontestservice(#HeaderParam("X-TOKENID") tokenId: String,
#QueryParam("clientId") clientId: String):com.test.MyResultClass = {
val response= new com.test.MyResultClass
[...]
response
}
How can I add the cache control to the response of myjsontestservice service? Do I need to use a filter and append the cachecontrol once the response has been created by jersey?
thanks million
Flavio
You would still need to return a Response object.
def somejson() : Response = {
val builder = Response.ok(new com.test.MyResultClass);
val cc = new CacheControl()
cc.setMaxAge(60)
cc.setNoCache(false)
builder.cacheControl(cc).build()
}
Jersey's interceptors will automatically convert your class into a JSON object.