Mockito returning null value for Future - mockito

I am unit-testing a controller in a play-framework application.
The controller uses a repository and I am mocking the repository as follows
val mockUserRepository = mock(classOf[UsersRepository])
when(mockUserRepository.findOne(userKeys)).thenReturn(Future{Some(user)})
when(mockUserRepository.save(user)).thenReturn(Future(Some(user)))
Then I run the following test. In the test, controller.signupUser(request) calls the findOne method of the repository as follows
val findUserFuture: Future[Option[User]] = userRepo.findOne(userKeys)
println("user future is ",findUserFuture)
findUserFuture.flatMap { (userOption: Option[User]) => //this crashes because findUserFuture is null)
But findOne returns a null instead of a dummy Future{user}
"User signup request with body" should {
"return OK and user profile if the signup profile data is correct" in {
val jsonBody = Json.parse(
"""
{
"external-profile":{
"email":"test#test.com",
"firstname":"fn",
"lastname":"ln",
"password":"aA1!1111"
}
}
""")
//val jsonBody = Json.toJson(signupInfo)
val request: Request[AnyContentAsJson] = FakeRequest("POST", "ws/users/signup",Headers(("someH"->"someV")),new AnyContentAsJson(jsonBody))
println("sending sign up request ", request)
//request.body = signupInfo
val response: Future[Result] = controller.signupUser(request)
val responseBodyAsJsValue:JsValue = contentAsJson(response)
println("received response of sign up ", responseBodyAsJsValue)
}
}
error
received profile
UserProfile(None,ExternalUserProfile(test#test.com,fn,ln,Some(aA1!1111)))
checking if the user with the following details exists LoginInfo(credentials,test#test.com)
returning id 116 for name test#test.com
(user future is ,null)
java.lang.NullPointerException was thrown.
java.lang.NullPointerException
at controllers.UserController.$anonfun$signupUser$1(UserController.scala:116)
What I might be doing wrong?

The issue apparently was the I wasn't using when correctly.
I read that "
Mockito allows to configure the return values of its mocks via a fluent API. Unspecified method calls return "empty" values:
null for objects
0 for numbers
false for boolean
empty collections for collections
Mocks can return different values depending on arguments passed into a method. The when(…​.).thenReturn(…​.) method chain is used to specify a a return value for a method call with pre-defined parameters.
"
when expects the method as well as the exact arguments. So if I want to call findUser(userkey) where userkey's value is say 1 in the actual call then I need to write when(findUser(1)) or userKey=1; findUser(userKey)).
In my wrong implementation, I had set userkey as
UserKeys(1,"test#test.com",loginInfo,"","")
but the call to findUser was with value
UserKeys(116,"d#d.com",loginInfo,"fn","ln")
I changed the userkey value in test and it worked
val userKeys = UserKeys(utilities.bucketIDFromEmail(email)/*returns 116*/,"d#d.com",loginInfo,"fn","ln")
when(mockUserRepository.findOne(userKeys)).thenReturn(Future{Some(user)})
when(mockUserRepository.save(user)).thenReturn(Future(Some(user)))

Related

Gatling Rest API Testing - retrieve a value from json response and add it to the list, iterate through list

I am new to Gatling, I am trying to do the performance testing for couple of rest calls. In my scenario I need to extract a value from json response of the 1st call and add those values to the list after looping for few times. Again after looping for few times and adding the values into the list, I want to reuse each value in my next rest call by iterating over the values in the list. Can anyone please suggest on how to implement this. I tried something as below,
var datasetIdList = List.empty[String]
val datasetidsFeeder = datasetIdList.map(datasetId => Map("datasetId" -> datasetId)).iterator
def createData() = {
repeat(20){
feed("").exec(http("create dataset").post("/create/data").header("content-type", "application/json")
.body(StringBody("""{"name":"name"}"""))
.asJson.check(jsonPath("$.id").saveAs("userId"))))
.exec(session => { var usrid = session("userId").as[String].trim
datasetIdList:+= usrid session})
}}
def upload()= feed(datasetidsFeeder).exec(http("file upload").post("/compute-metaservice/datasets/${datasetId}/uploadFile")
.formUpload("File","./src/test/resources/data/File.csv")
.header("content-type","multipart/form-data")
.check(status is 200))
val scn = scenario("create data and upload").exec(createData()).exec(upload())
setUp(scn.inject(atOnceUsers(1))).protocols(httpConf)
}
I am seeing an exception that ListFeeder is empty when trying to run above script. Can someone please help
Updated Code:
class ParallelcallsSimulation extends Simulation{
var idNumbers = (1 to 50).iterator
val customFeeder = Iterator.continually(Map(
"name" -> ("test_gatling_"+ idNumbers.next())
))
val httpConf = http.baseUrl("http://localhost:8080")
.header("Authorization","Bearer 6a4aee03-9172-4e31-a784-39dea65e9063")
def createDatasetsAndUpload() = {
repeat(3) {
//create dataset
feed(customFeeder).exec(http("create data").post("/create/data").header("content-type", "application/json")
.body(StringBody("""{ "name": "${name}","description": "create data and upload file"}"""))
.asJson.check(jsonPath("$.id").saveAs("userId")))
.exec(session => {
val name = session("name").asOption[String]
println(name.getOrElse("COULD NOT FIND NAME"))
val userId = session("userId").as[String].trim
println("%%%%% User ID ====>"+userId)
val datasetIdList = session("datasetIdList").asOption[List[_]].getOrElse(Nil)
session.set("datasetIdList", userId :: datasetIdList)
})
}
}
// File Upload
def fileUpload() = foreach("${datasetIdList}","datasetId"){
exec(http("file upload").post("/uploadFile")
.formUpload("File","./src/test/resources/data/File.csv")
.header("content-type","multipart/form-data")
.check(status is 200))
}
def getDataSetId() = foreach("${datasetIdList}","datasetId"){
exec(http("get datasetId")
.get("/get/data/${datasetId}")
.header("content-type","application/json")
.asJson.check(jsonPath("$.dlp.dlp_job_status").optional
.saveAs("dlpJobStatus")).check(status is 200)
).exec(session => {
val datastId = session("datasetId").asOption[String]
println("request for datasetId >>>>>>>>"+datastId.getOrElse("datasetId not found"))
val jobStatus = session("dlpJobStatus").asOption[String]
println("JOB STATUS:::>>>>>>>>>>"+jobStatus.getOrElse("Dlp Job Status not Found"))
println("Time: >>>>>>"+System.currentTimeMillis())
session
}).pause(10)
}
val scn1 = scenario("create multiple datasets and upload").exec(createDatasetsAndUpload()).exec(fileUpload())
val scn2 = scenario("get datasetId").pause(100).exec(getDataSetId())
setUp(scn1.inject(atOnceUsers(1)),scn2.inject(atOnceUsers(1))).protocols(httpConf)
}
I see below error when I try to execute above script
[ERROR] i.g.c.s.LoopBlock$ - Condition evaluation crashed with message 'No attribute named 'datasetIdList' is defined', exiting loop
var datasetIdList = List.empty[String] defines a mutable variable pointing to a immutable list.
val datasetidsFeeder = datasetIdList.map(datasetId => Map("datasetId" -> datasetId)).iterator uses the immutable list. Further changes to datasetIdList is irrelevant to datasetidsFeeder.
Mutating a global variable with your virtual user is usually not a good idea.
You can save the value into the user's session instead.
In the exec block, you can write:
val userId = session("userId").as[String].trim
val datasetIdList = session("datasetIdList").asOption[List[_]].getOrElse(Nil)
session.set("datasetIdList", userId :: datasetIdList)
Then you can use foreach to iterate them all without using a feeder at all.
foreach("${datasetIdList}", "datasetId") {
exec(http("file upload")
...
}
You should put more work in your question.
Your code is not syntax-highlighted, and is formatted poorly.
You said "I am seeing an exception that ListFeeder is empty" but the words "ListFeeder" are not seen anywhere.
You should post the error message so that it's easier to see what went wrong.
In the documentation linked, there is a Warning. Quoted below:
Session instances are immutable!
Why is that so? Because Sessions are messages that are dealt with in a multi-threaded concurrent way, so immutability is the best way to deal with state without relying on synchronization and blocking.
A very common pitfall is to forget that set and setAll actually return new instances.
This is why the code in the updated question doesn't update the list.
session => {
...
session.set("datasetIdList", userId :: datasetIdList)
println("%%%% List =====>>>" + datasetIdList.toString())
session
}
The updated session is simply discarded. And the original session is returned in the anonymous function.

How to test for Empty array value in Unirest json Response

I have the following code snipet used in Jira Script Runner cloud
String _userId
def result = get(graph_base_user_url + "?")
.header("Authorization","Bearer " + AuthToken )
.queryString("\$filter","mail eq '$userEmail'")
.asJson()
if (result.getStatus().toString() =="200")
{
**if (result.getBody().value){ // <<<<< is Value is not empty ???
_userId=result.getBody().value[0].id
}**
else
_userId="-1" // user does not exist
}
// user ID not found : error 404
if (result.getStatus().toString()=="404")
_userId="User not found"
This code is returning in the result.getBody() the following output
{"#odata.context":"https://graph.microsoft.com/v1.0/$metadata#users","value":[]}
What I am trying to achieve is to test if the value array of the response is empty or not and if not empty I need to fetch the first element item as value[0].Id, but I could not get it correctly
How can I define my code in BOLD above to perform my correct test ?
Error I get from my code is : " Value is not a property of JsonNode object
Thanks for help
regards
from official doc http://kong.github.io/unirest-java/#responses
String result = Unirest.get("http://some.json.com")
.asJson()
.getBody()
.getObject()
.getJSONObject("car")
.getJSONArray("wheels")
.get(0)
so, something like this should work for you:
def a = result.getBody().getObject().getJSONArray("value")
if(a.length()>0) _userId = a.get(0).get("id")

How to catch null value on http response

I have the following code method which is used to test for an existing user in MSGraph API
public String getGuestUserId(String AuthToken,String userEmail){
String _userId
def http = new HTTPBuilder(graph_base_user_url + "?")
http.request(GET) {
requestContentType = ContentType.JSON
//uri.query = [ $filter:"mail eq '$userEmail'"].toString()
uri.query=[$filter:"mail eq '$userEmail'"]
headers.'Authorization' = "Bearer " + AuthToken
response.success = { resp, json ->
//as the retunr json alue is an array collection we need to get the first element as we request all time one record from the filter
**_userId=json.value[0].id**
}
// user ID not found : error 404
response.'404' = { resp ->
_userId = 'Not Found'
}
}
_userId
}
This method works fine when the user is existing and will return properly from the success response the user ID property.
The issue I get is that if the user is not existing, the ID field is not existing either and the array is empty.
How can I handle efficiently that case and return a meaning full value to the caller like "User Does not exist"
I have try a catch exception in the response side but seems doe snot to work
Any idea how can I handle the test like if the array[0] is empty or does not contains any Id property, then return something back ?
Thanks for help
regards
It seems to be widely accepted practice not to catch NPE. Instead, one should check if something is null.
In your case:
You should check if json.value is not empty
You also should check if id is not null.
Please also note that handling exceptions in lambdas is always tricky.
You can change the code to:
http.request(GET) {
requestContentType = ContentType.JSON
uri.query=[$filter:"mail eq '$userEmail'"]
headers.'Authorization' = "Bearer " + AuthToken
if (json.value && json.value[0].id) {
response.success = { resp, json -> **_userId=json.value[0].id** }
} else {
// Here you can return generic error response, like the one below
// or consider more granular error reporting
response.'404' = { resp -> _userId = 'Not Found'}
}
}

How to obtain virtual user id/details in gatling?

I am new to Gatling and Scala and I need your advice.
I would like to obtain load test for n-users. Each user have to send request for creating different accounts. This is obtained by sending json file with appropriate array of objects ('entries' in our case).
Each single user must send different login as our backend system is checking if username is unique. Somehow we have to be sure that gatling is sending different data for each virtual user and also for each entries as well.
We noticed that there us session element which represents virtual user's state. Problem is that code showed below will not work as Exec structure used with expression function does not send any request.
There is section that could work but I do not know how to determine third parameter to distinguish virtual user id. Please find below simple json file structure used for this test
{
"entries": [
{
"userName": "some user name",
"password": "some password"
}
}
and scala code with my comments
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class UserCreationTest extends Simulation {
val profilesNumber = 2
val virtualUsers = 2
val httpConf = http
.baseURL("some url")
.acceptHeader("application/json")
.basicAuth("username", "password")
// This method will multiply 'entries' section in JSON 'entriesNumber' times
def createJsonUserEntries(entriesNumber: Int, users: List[String], userId : Long): String = {
val header = """{"entries": ["""
val footer = """]}"""
val builder = StringBuilder.newBuilder
for (i <- 0 until entriesNumber) {
val userIndex = (userId.toInt - 1) * entriesNumber + i
val userName = users(userIndex).get
val apiString =
s"""{
"userName": "${userName}"
"password": "password"
}"""
builder.append(apiString)
if (i != entriesNumber) {
builder.append(",")
}
}
header + builder.toString() + footer
}
// We do have method for generating user names based on profilesNumber and virtualUsers variables
// but for sake of this example lets hardcode 4 (profilesNumber * virtualUsers) user names
val usersList = List("user-1", "user-2", "user-3", "user-4")
//This will throw exception as no request was send. According to documentation function block is used to debugging/editing session
val scn = scenario("Create WiFi User Profile")
.exec(session => {
http("CreateUserProfile")
.post("/userProfiles/create/")
.body(StringBody(
createJsonUserEntries(profilesNumber, userslList, session.userId).toString
)
).asJSON
session})
// This exec block will send a request but I do not know how to determine third param that should be virtual user Id
// To run this section please comment previous whole scenario block
/*
val scn = scenario("")
.exec(http("CreateUserProfile")
.post("/userProfiles/create/")
.body(StringBody(
createJsonUserEntries(profilesNumber, emailList, ???).toString
)
).asJSON
)
*/
setUp(scn.inject(atOnceUsers(virtualUsers)).protocols(httpConf))
}
Can you help me on that please? Is there any other way to do that in gatling? Thank you very much in advance
so you are trying to have each user have a unique userId?
you could create a feeder that does this
var userIdFeeder = (1 to 999999).toStream.map(i => Map("userId" -> i)).toIterator
val scn = scenario("")
.feed(userIdFeeder)
.exec(http("CreateUserProfile")
.post("/userProfiles/create/")
.body(StringBody(
createJsonUserEntries(profilesNumber, emailList, "${userId}").toString
)
).asJSON
)

FakeRequest seem to be Null when passed to a controller in unit test

Getting Null Pointer error when unit testing controller. The issue seem to be in the line
def signupUser = Action.async{
implicit request => { //requeust seem to be null
I suspect so because the stacktrace from previous tests point to implicit request line. But I don’t know what could be wrong in this because I am using FakeRequest like so val request = FakeRequest("POST", "/ws/users/signup").withJsonBody(Json.parse("""{"bad": "field"}"""))
Following is a snippet of a controller I want to unit-test
class UserController #Inject()(userRepo: UsersRepository,cc: ControllerComponents, silhouette: Silhouette[JWTEnv])(implicit exec: ExecutionContext) extends AbstractController(cc){
def signupUser = Action.async{
implicit request => {...}
}
I only want to test that the controller returns an error when it gets a request without json body. Thus I don't need Silhouette and I want to mock it. But I am getting null pointer error.
Following is the way I have written my unit test case is
class UserControllerUnitSpec extends PlaySpec with MockitoSugar {
"User signup request with non-JSON body" should {
"return 400 (Bad Request) and the validation text 'Incorrect body type. Body type must be JSON'" in {
val email = "d#d.com"
val loginInfo = LoginInfo(CredentialsProvider.ID, email);
val passwordInfo = PasswordInfo("someHasher","somePassword",Some("someSalt"))
val internalUserProfile = InternalUserProfile(loginInfo,true,Some(passwordInfo))
val externalUserProfile = ExternalUserProfile(email,"d","d",Some("somePassword"))
val userProfile = UserProfile(Some(internalUserProfile),externalUserProfile)
val user = User(UUID.randomUUID(),userProfile)
println("testing with mocked User value",user);
val mockUserRepository = mock[UsersRepository]
when(mockUserRepository.findUser(loginInfo)).thenReturn(Future(Some(user)))
when(mockUserRepository.saveUser(user)).thenReturn(Future(Some(user)))
val mockSilhouette = mock[Silhouette[JWTEnv]] //I am probably not doing this correctly
val mockControllerComponents = mock[ControllerComponents] //I am not sure if this is correct either
val controller = new UserController(mockUserRepository,mockControllerComponents,mockSilhouette)
val result:Future[Result] = controller.signupUser(FakeRequest())
(result.map(response => {
println("response: ",response)
response mustBe BadRequest
}))
}
}
}
Regarding mockControllerComponents, Helpers.stubControllerComponents can be used instead of a mock:
val mockControllerComponents = Helpers.stubControllerComponents()
Regarding mockSilhouette, you have to setup the mock using when(...).thenReturn(...) similarly to how you have done it formockUserRepository, that is, inspect all the usages of silhouette inside signupUser and provide the appropriate method stubs:
val mockSilhouette = mock[Silhouette[JWTEnv]]
when(mockSilhouette.foo(...)).thenReturn(...)
when(mockUserRepository.bar(...)).thenReturn(...)
...
(Posted solution on behalf of the question author).
Here is the answer which worked. Thanks Mario.
class UserControllerUnitSpec extends PlaySpec /*with MockitoSugar*/ {
"User signup request with non-JSON body" should {
"return 400 (Bad Request) and the validation text 'Incorrect body type. Body type must be JSON'" in {
val email = "d#d.com"
val loginInfo = LoginInfo(CredentialsProvider.ID, email);
val passwordInfo = PasswordInfo("someHasher","somePassword",Some("someSalt"))
val internalUserProfile = InternalUserProfile(loginInfo,true,Some(passwordInfo))
val externalUserProfile = ExternalUserProfile(email,"d","d",Some("somePassword"))
val userProfile = UserProfile(Some(internalUserProfile),externalUserProfile)
val user = User(UUID.randomUUID(),userProfile)
println("testing with mocked User value",user);
val mockUserRepository = mock(classOf[UsersRepository])
// when(mockUserRepository.findUser(loginInfo)).thenReturn(Future(Some(user)))
// when(mockUserRepository.saveUser(user)).thenReturn(Future(Some(user)))
// val mockSilhouette = mock(classOf[Silhouette[JWTEnv]])
val mockControllerComponents = Helpers.stubControllerComponents()//mock(classOf[ControllerComponents])
/*
The controller needs Silhouette. Using Silhouette's test kit to create fake instances.
If you would like to test this controller, you must provide an environment that can handle your Identity and Authenticator implementation.
For this case Silhouette provides a FakeEnvironment which automatically sets up all components needed to test your specific actions.
You must only specify one or more LoginInfo -> Identity pairs that should be returned by calling request.identity in your action and
the authenticator instance that tracks this user.
*/
//User extends Identity trait
/*
Under the hood, the environment instantiates a FakeIdentityService which stores your given identities and returns it if needed.
It instantiates also the appropriate AuthenticatorService based on your defined Authenticator type. All Authenticator services are real
service instances set up with their default values and dependencies.
*/
implicit val sys = ActorSystem("MyTest")
implicit val mat = ActorMaterializer()
implicit val env = FakeEnvironment[JWTEnv](Seq(loginInfo->user))
val defaultParser = new mvc.BodyParsers.Default()
val securedAction = new DefaultSecuredAction(new DefaultSecuredRequestHandler(new DefaultSecuredErrorHandler(stubMessagesApi())),defaultParser)
val unsecuredAction = new DefaultUnsecuredAction(new DefaultUnsecuredRequestHandler(new DefaultUnsecuredErrorHandler(stubMessagesApi())),defaultParser)
val userAware = new DefaultUserAwareAction(new DefaultUserAwareRequestHandler(),defaultParser)
val mockSilhouette = new SilhouetteProvider[JWTEnv](env,securedAction,unsecuredAction,userAware)
val controller = new UserController(mockUserRepository,mockControllerComponents,mockSilhouette)
val request = FakeRequest("POST","ws/users/signup")
println("sending request",request)
//val result = controller.someMethod()
val result:Future[Result] = controller.signupUser(request)
status(result) mustBe BAD_REQUEST
}
}
}

Resources