Cucumber (Gherkin): How to use parameters of type non string (Long) in test steps? - gherkin

I'm trying to write some Cucumber tests in order to get familiarized with the Gherkin language.
Here is a feature sample:
Scenario: Get a customer
When an user wants to get a customer <id>
Then an HTTP 200 status together with the requested customer data is returned
And here is the associated step:
#When("an user wants to get a customer {long}")
public void anUserWantsToGetACustomer(Long id)
{
...
}
Running the verify goal raises the following exception:
[ERROR] Get a customer Time elapsed: 0.023 s <<< ERROR!
io.cucumber.junit.UndefinedStepException:
The step "an user wants to get a customer <long>" is undefined. You can implement it using the snippet(s) below:
#When("an user wants to get a customer <id>")
public void anUserWantsToGetACustomer_id() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
Obviously, it doesn't understand that the step method need to take a parameter of type Long. However, for parameter of type String it works, for example:
Scenario: Get a customer
When an user wants to get a customer "<id>"
Then an HTTP 200 status together with the requested customer data is returned
...
#When("an user wants to get a customer {string}")
public void anUserWantsToGetACustomer(String id)
{
...
}
So, what kind of syntax should I use here in order that my tests accepts a Long parameter ?
Kind regards,
Seymour

You can use {long} in your step defs
Scenario: test long type
Given I log the type of 41
#Given("I log the type of {long}")
public void logType(Long testLong ) {
System.out.println("type of 41 is:"+ testLong.getClass());
}
prints
type of 41 is:class java.lang.Long
This also works
Scenario Outline: test long type
Given I log the type of <id>
Examples:
|id|
| 41 |
#Given("I log the type of {long}")
public void logType(Long testLong ) {
System.out.println("type of " +testLong +" is:"+ testLong.getClass());
}

Related

Using VRS for concurrent request

We need to use a single instace of VRS to support concurrent request.
We have a requirement where multiple different users should be able to create a route plan for different vehicles and locations same time. However, looking at VRS functionality, I am not able to understand how applications supports it. For demo, when I create a different route using different browser, it always merges first and second request and give one single result.
Just a little more elobration on the question:
We are aiming to convert requests as REST API endpoints which will be invoked by different uses same time for their usecase.
Eg. Request 1: Vehicle 1&2 with 50 locations. VRS can calculate route & give one message with all detailed calculations for request1.
Request 2: Vehicle 3 & 4 with 40 locations. So VRS can calculate route which later we can get as one message with all detailed calculations limited to request 2.
Both requests can be submitted same time & application should considered as separate requests without getting merged.
Is there a way to add request ID or any other paramaters to achive this?
For multi-tenant solving, the SolverManager API is ideal:
public class TimeTableService {
// tenantId is Long, but it can also be String or UUID
private SolverManager<TimeTable, Long> solverManager;
// Returns immediately, call it for every dataset
public void solveBatch(Long tenantId) {
solverManager.solve(tenantId,
// Called once, when solving starts
this::findById,
// Called once, when solving ends
this::save);
}
public TimeTable findById(Long tenantId) {...}
public void save(TimeTable timeTable) {...}
}

Difference between EnsureSuccessStatusCode and Assert.Equal(HttpStatusCode.OK, response.StatusCode) in XUnit ASP.Net Core WebAPI Tests

I read in a Book (ISBN 1838550313, 9781838550318 S.315) that they check a WEB-API Request with both EnsureSuccessStatusCode() and Assert.Equal(HttpStatusCode.OK, ..) in one validation Method. But is the second Assert call not unnecessary to check if the HTTP-Status is 200 or not? What is the difference and what is the best practice?
HttpResponseMessage.EnsureSuccessStatusCode is implemented like this:
public HttpResponseMessage EnsureSuccessStatusCode()
{
if (!IsSuccessStatusCode)
{
throw new HttpRequestException(…, inner: null, _statusCode);
}
return this;
}
So it just checks the value of IsSuccessStatusCode which is implemented like this:
public bool IsSuccessStatusCode
{
get { return ((int)_statusCode >= 200) && ((int)_statusCode <= 299); }
}
So a status code is considered to be successful, if it is in the range [200, 299]. This matches the definition of the HTTP status codes.
If the status code value is not a successful code, then the EnsureSuccessStatusCode method will throw an exception. So it is a quick way to stop the execution in cases where the request failed.
Asserting for equality with HttpStatusCode.OK checks if the status code is exactly 200. This also means that other successful codes would be rejected. Whether that is an appropriate thing to do depends on the API you are testing. Many RESTful APIs will often return different successful status codes depending on what happened. For example, an API might return “201 Created” to express that a resource has been created.
If the test wants to explicitly ensure that the response has a status code “200 OK”, then calling EnsureSuccessStatusCode is not needed. Otherwise, if you want to accept any successful status code, just calling EnsureSuccessStatusCode will be enough for the test since a thrown exception will usually fail the test.

Implicit cast operator in ActionResult<bool> not working

I am following this guide to build my controllers. I do the following.
This is my controller:
// GET api/sth/{sthId}/isValid
[HttpGet("{sthId: int}/isValid")]
[ProducesResponseType(StatusCodes.Status200OK)]
[MyAuthorizeFilter]
public ActionResult<bool> Whatever(int sthId)
{
return this.myService.Whatever(sthId);
}
Theoretically, this should be converted to an Ok() ActionResult. However, If I write the following unit test:
[Fact]
public void Whatever()
{
this.myServiceMock.Setup(x => x.Whatever(It.IsAny<int>())).Returns(true);
-> I DEBUG HERE -> var result = this.myController.Whatever(1);
Assert.IsType<OkObjectResult>(result);
Assert.True((bool)result.Value);
}
I see that my result is an ActionResult<bool> indeed, whose Value is true as expected, but result.Result is null. So: no Ok action result whatsoever.
What am I missing? Do I have to write explicitly the return Ok() to get it? With the sentence
Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>. T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.
in the documentation I thought it was not necessary...?
The ActionResult<TValue> class:
wraps either an[sic] TValue instance or an ActionResult.
See also the source, its constructors assign either Value or Result, never both.
The MVC pipeline will assign a success status code to the response if no status code was explicitly set. But I can't find documentation for that claim.
This means the response as obtained in this test won't have a status code or OkActionResult anywhere. You can convert it to an ObjectResult, but that won't have a status code.
If you use something like swagger you will indeed get an OK from the server.
This happens to you because you dont perform an http request you simple call a method(your controller method) and you get a return type. You dont create a web server or something so no http status code is generated by .net core.
If you want to get status codes you should write test using http requests. Generally you could look up something like postman to perform your testing.

Passing a variable from one feature file into another as a part of request URL(not query parameter) in Karate

I have a feature that generates a vehicle id and is stored as a variable in the feature. I want to pass this id as a part of the request URL in another feature as a sort of a teardown activity.
This is how I called it from a feature called activateVehicle.feature
Scenario : Activate a vehicle
* header X-API-Key = apiKey
* def result = callonce read('createVehicle.feature')
* def vehicleId = result.vId
# some workflow steps
........
........
........
# tear down - delete the vehicle created
* call read('deleteVehicle.feature'){ vehcileId: '#(vehicleId)' }
In the called feature - deleteVehicle.feature
Scenario: Delete a vehicle
* header X-API-Key = apiKey
* def myurl = 'https://xxx/vehicle'+ vehicleId +'?permanent=yes'
Given myurl
And request ''
When method delete
Then status 200
Am I right in the approach? I want to reuse deleteVehicle.feature in other workflows as well and hence not doing this operation in the same activateVehicle.feature(which would have been very easy). I referred to the documentation too but it shows how we can use the variables in in the request body but not as a variable that can be used anywhere in the called feature. I don't want to use it in the request body (but want to use it as a part of the request URL) For example:
Scenario:
Given url loginUrlBase
And request { userId: '#(username)', userPass: '#(password)' }
I also referred to How can I call a variable from one feature file to another feature file using Karate API Testing. I followed suit for a solution but am getting a javascript error:
feature.deleteVehicle: -unknown-:11 - javascript evaluation failed:
'https://xxx/vehicle'+ vehicleId +'?permanent=yes', ReferenceError: "vehicleId"
is not defined in <eval> at line number 1
feature.SVT: SVT.feature:80 - javascript evaluation failed: vehicleId: '#(vehicleId)' }, <eval>:1:14 Expected eof
but found }
vehicleId: '#(vehicleId)' }
^ in <eval> at line number 1 at column number 14
Can someone kindly help and advise please?
Can you simplify your example ? The only thing I can make out is you need a space after the call feature and before the call argument:
* call read('deleteVehicle.feature') { vehcileId: '#(vehicleId)' }
The pattern we generally recommend is to setUp not tearDown as tearDown has a risk of not executing if you had an error. That said, please see hooks: https://github.com/intuit/karate#hooks
Sometimes you should just keep it simple and call a feature (with args) only where you need it.

karate | xml post method exeuction

I’m having issue with xml post request where post method is not executed. When I try to post same request body in post man it worked.My test is success with 200 but actual request is not executed.
Please let me know if I’m missing
To pass the request body,I’m calling through java object and payload is correctly constructed and printed.In execution test is success and doesn’t print response.But actually test is not executed.
Only headers are printed.
***************** create-user.feature*****************
Feature: create ims user for provided country
Requires country code,
Background:
# load secrets from json
* def createuser = Java.type('com.user.JavaTestData')
* def create = createuser.createUser("US")
Scenario: get service token
Given url imscreateuserurl
And request create
When method post
Then status 200
* print response
***************** create-user.feature*****************
Here is java class
public class JavaTestData {
private static final Logger logger = LoggerFactory.getLogger(JavaTestData.class);
public static String createUser(String countryCodeInput) {
logger.debug("create user for country code input", countryCodeInput);
Unless you post a full working example, no one can help you. Pretty clear that the value of create is null or empty.
Also I personally think you are wasting your time using Java. The whole point of Karate is to avoid using Java as far as possible.
Look at these examples for ideas: https://github.com/intuit/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/xml/xml.feature
Edit: also refer to the doc on type-conversion: https://github.com/intuit/karate#type-conversion
#Peter, here is my feature file
Feature: create ims user for provided country
Requires country code,
Background:
# load secrets from json
* def createuser = Java.type('com.adobe.imscreateuser.JavaTestData')
* def create = createuser.createUser("US")
Scenario: get service token
Given url imscreateuserurl
And header Content-Type = 'application/xml; charset=utf-8'
And request create
When method post
Then status 200
* print response
I have performed print for create and showing complete payload.At when method post -> statement its going as null or empty...
Not sure where it is missing