Cucumber feature file - describe aggregation - cucumber

I am new in the cucumber world and i just want to describe an aggregation for the context of my scenario. I have a model and a DataTransferObject like the one below and i want to write an REST Api which returns a JSON.
public class Product {
int id;
String name;
double basePrice;
ProductCategory category;
}
public class ProductCategory {
int id;
String name;
List<Customization> possibleCustomizationsForCategory;
}
public class Customization {
int id;
String characteristic;
double additionalPrice;
}
public class ProductDTO {
int productId;
String productName;
double basePrice;
Size size;
int productCategoryId;
String productCategoryName;
List<Integer> possibleCustomizationIds;
}
I want to write something like this:
Given the system has persisted the following products
When a client requests GET /products
Then he will receive a JSON like the following:
"""
[
{
"productId": 1,
"productName": "Kaffee",
"basePrice": 2.00,
"size": "SMALL",
"productCategoryId": 1,
"productCategoryName": "Hot Drinks",
"possibleCustomizationIds": [1,2,3,4,5,6]
},
{
"productId": 2,
"productName": "Kaffee",
"basePrice": 3.0,
"size": "MEDIUM",
"productCategoryId": 1,
"productCategoryName": "Hot Drinks",
"possibleCustomizationIds": [1,2,3,4,5,6]
}
{
"productId": 3,
"productName": "Cookie",
"basePrice": 1.0,
"size": "SMALL",
"productCategoryId": 1,
"productCategoryName": "Biscuite",
"possibleCustomizationIds": [8,9]
}
]
"""
But how can I write the Given part and describe the Object in a way that it will be clear that there are three different classes with aggregations?

I would keep Gherkin in a more business level language that describes the problem you are trying to solve.
I would then have the step definitions describe the solution to the problem.
Therefore, your gherkin could be:
Given the following products are in stock
| Product |
| Small Kaffee |
| Medium Kaffee |
| Small Cookie |
When I get a list of stock
Then I the three products should be shown as in stock
And I should be able to view the details about them
I have assumed this is a stock control situation. This Scenario could then be ran against a database, web api, or the GUI and should still be true, just will a different solution in place.. i.e. using different step definitions.

Related

Writing raw JSON to CosmosDB and an Azure Function

I want to take the raw JSON body from an HTTP post and write it directly into my CosmosDB.
Let's say the data looks like this:
{
"id": "123456",
"storeName": "City Bar and Grille",
"invoiceTotal": 65
}
However, the documentsOut.AddAsync command uses a format like this:
wait documentsOut.AddAsync(new
{
// create a random ID
id = System.Guid.NewGuid().ToString(),
body = sourceJson
});
And then I end up with a document that looks like this:
{
"id": "0e99d3ab-1956-4c0a-8ec1-99de5c987555",
"body": {
"id": "123456",
"storeName": "City Bar and Grille",
"invoiceTotal": 65
}
}
What I really want is to end up with this:
{
"id": "123456",
"storeName": "City Bar and Grille",
"invoiceTotal": 65
}
I'd like to drop the id = System.Guid.NewGuid().ToString() completely (which should not be hard).
How can I pass the raw JSON through without needing to add it to some parent node (such as body)?
Just to formalize my comment as an answer: You're specifically creating the body property of the Cosmos DB document you're creating:
wait documentsOut.AddAsync(new
{
// create a random ID
id = System.Guid.NewGuid().ToString(),
body = sourceJson
});
At the same time, you're ignoring the incoming ID. Since you wanted to preserve that ID, You can copy the ID over (as long as it remains unique within the partition) instead of generating a new GUID, and also grab individual properties from sourceJson to avoid the nested body element:
wait documentsOut.AddAsync(new
{
id = sourceJson.id,
storeName = sourceJson.storeName,
invoiceTotal = sourceJson.invoiceTotal
});
Using a similar example as shared by you in the question.
We can create a Model class with properties which want to store in database.
public class StoreDetails : TableEntity
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("storeName")]
public string StoreName { get; set; }
[JsonProperty("invoiceTotal")]
public string InvoiceTotal { get; set; }
}
Then can create object of model and pass that object to AddAsync()method. As shown in below screenshot.
var item = new StoreDetails
{
Id = Guid.NewGuid().ToString(),
StoreName = data.StoreName,
InvoiceTotal = data.InvoiceTotal
};
await storeDetailOut.AddAsync(item);
and when we triggered post API, got response as shown below.
As finally we can see the same record is stored in CosmosDB.

how effciently read soap web service response with nested objects using streams

I consider a very easy task parse a nested object asnwered by a soap webservice using Java 8 streams. Nevertheless, I am quite confused when I think about the correct or most appropriate approach to use. I know it will depend on circunstances and there will never be a simple recipe. I have been reading for the last two weeks where and how to use stream but I couldn't reach a final conclusion about few options. I put bellow four approaches I would appreciatte if someone could give technical opnion if I understood correctly the real application based on very common requirements when dealing with soap client.
I am not loking for a simple answer like "Here I do successfully this way so you can copy and paste similar idea". I am really interested to understand if I am applying properly what I have read so far.
Firstly, my nested objects answered by web service:
//first level
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "OndernemingAlgemeenType", propOrder = {
"adressen",
... others properties
})
#XmlSeeAlso({
Onderneming20Type.class
})
public class OndernemingAlgemeenType
{
#XmlElement(name = "Adressen")
protected AdresOndernemingLijstType adressen;
... others elements
}
//second level that returns a list
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AdresOndernemingLijstType", propOrder = {
"adres"
})
public class AdresOndernemingLijstType {
#XmlElement(name = "Adres", required = true)
protected List<AdresOndernemingType> adres;
...
}
// third level used to filter the list and return just one AdresOndernemingType
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AdresOndernemingType", propOrder = {
"type"
})
public class AdresOndernemingType
extends AdresOndernemingBasisType{
#XmlElement(name = "Type", required = true)
protected TypeAdresOndernemingType type;
}
// fourth level
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AdresOndernemingBasisType", propOrder = {
... not relevant for this question
})
#XmlSeeAlso({
AdresOndernemingType.class
})
public class AdresOndernemingBasisType
extends AdresBasisType
{
... not relevant for this question
}
// fifth level and finally, the desired fields (street and city)
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AdresBasisType", propOrder = {
"straat", //street
"gemeente" //city
})
#XmlSeeAlso({
AdresOndernemingDeelnemingInType.class,
AdresOndernemingBasisType.class
})
public class AdresBasisType {
#XmlElement(name = "Straat")
protected StraatRR20Type straat;
#XmlElement(name = "Gemeente")
protected GemeenteOptioneel20Type gemeente;
// Approaches with its understanding
Approach 1:
I understand that this is null exception safe.
I mean, in case either getAdressen or getAdres is null there will be no exception at all and no address printed.
private void printOptionalDidactic(){
Optional<AdresOndernemingLijstType> op = Optional.ofNullable(onderneming.getAdressen());
op.map(AdresOndernemingLijstType::getAdres).get().stream().filter(Objects::nonNull)
.filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
.map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
Approach 2:
Assuming that there will be never a null element (minOccurs="1" in xsd for all) so using Optional would be pointless
private void printNoOptionalDidactic(){
onderneming.getAdressen().getAdres().stream()
.filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
.map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
Approach 3:
Assuming I want to print all streets and I don't care about filtering, I understand there is no advantage at all to use flatMap before forEach
Replace nested loop with Java 8 flatmap
private void printForEachDidactic(){
onderneming.getAdressen().getAdres().stream()
.forEach(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
Approach 4
Since no shared resource is used by the predicates and functions used in the process,
I understand I could use parallelism. Nevertheless, provided that it is little data so I have no real gain on it
Should I always use a parallel stream when possible?
private void printParallelDidactic(){
onderneming.getAdressen().getAdres().parallelStream()
.filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
.map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
I wouldn't use map stream method when you really do not map elements of the stream (e.g. in approach 1 .map(x -> System.out.println...). Better call forEach, it is dedicated to execute code for each element of the stream.
Regarding your first approach, I think there will be a NoSuchElementException thrown if onderneming.getAdressen() is null. See implementation of Optional.get:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
Otherwise all approaches look valid from the code point of view. Of course I cannot say anything about your data model.
However, you do not need to apply Java 8 streams and lambdas just because Java 8 introduced them. For example, I wouldn't use streams in your approach 3. An old school for loop will do it, too (and is slightly more readable here IMO):
for (AdresOndernemingType x : onderneming.getAdressen().getAdres()) {
System.out.println("My street is: ".concat(x.getStraat())));
}
Regarding parallel streams, I wouldn't use parallel() except when I really need parallelism to gain performance on huge data sets or long running tasks.

Removing properties with null values

In my DocumentDb documents, I don't want to include properties with NULL values. For example, I have the following POCO class.
public class Person
{
[JsonProperty(PropertyName="id")]
public int PersonId {get; set;}
[JsonProperty(PropertyName="firstName")]
public string FirstName {get; set;}
[JsonProperty(PropertyName="middleName")]
public string MiddleName {get; set;}
[JsonProperty(PropertyName="lastName")]
public string LastName {get; set;}
}
Some people don't have middle names and when I save a person's document in my collection, I don't want the middle name to be included. Currently, a person without a middle name is saved as:
{
"id": 1234,
"firstName": "John",
"middleName": null,
"lastName": "Smith"
}
Is this normal behavior? If not, how do I NOT include the middle name property with a NULL value in my document?
P.S. All serialization/deserialization is handled by JSON.NET
You can do that when you initialize the Cosmos Client, there's a serialization option which is similar to the JSON.Net.
CosmosClient client = new CosmosClient(yourConnectionString, new CosmosClientOptions()
{
SerializerOptions = new CosmosSerializationOptions()
{
IgnoreNullValues = true,
}
});
I think I found the answer. Looks like I can tell JSON.NET to ignore properties with NULL values using
NullValueHandling = NullValueHandling.Ignore
Here's the documentation:
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size

Strange content in JSON deserialization result

Given this request DTO
public class CreateRecordRequest {
public Dictionary<string, object> Record { get; set; }
}
when I call the service passing this JSON
{
"Record": {
"File": {
"name": "DSC_3493_4_5.jpg",
"extension": ".jpg",
"size": 596002,
"rawFile": {}
},
"Notes": "",
"Type": ""
}
}
File has the deserialized value "{". Since ServiceStack has no way of knowing which object File maps to, I'm curious why it doesn't deserialize it as a dictionary ("{" is inexplicable). What is the easiest way to customize deserialization of a single value like this? I'm working with Kendo's upload control and this is the JSON it submits.
Because it's an object the Serializer doesn't know what type to dehydrate this into, you can force it to use a Dictionary<string,string> with:
JsConfig.ConvertObjectTypesIntoStringDictionary = true;

Unmarshal a single element list fails

I'm running a sample (which i can't find anymore) from Blaise Doughans blog on Glassfish 3 using EclipseLink 2.5 MOXy for JAXB service.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Company {
#XmlElementWrapper(name="employees")
#XmlElement(name = "employee", type=Employee.class)
private List<Employee> employees;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
private String id;
private String name;
}
I added some annotations to the classes, to produce the desired json structure:
{
"employees": [
{
"id": "1",
"name": "Jane Doe",
"report": []
}
]
}
When i try to unmarshal this JSON it sadly fails, returning an object with an empty employees list.
Adding another element to the JSON list OR removing the #XmlElementWrapper works.
But i want the key element to be named employees, so i have to use the wrapper annotation, or not?
Edit:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(Index.class);
return set;
}
#Override
public Set<Object> getSingletons() {
MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
moxyJsonProvider.setAttributePrefix("#");
moxyJsonProvider.setFormattedOutput(true);
moxyJsonProvider.setIncludeRoot(false);
moxyJsonProvider.setMarshalEmptyCollections(true);
moxyJsonProvider.setValueWrapper("$");
moxyJsonProvider.setWrapperAsArrayName(true);
HashSet<Object> set = new HashSet<Object>(1);
set.add(moxyJsonProvider);
return set;
}
}
I have confirmed the issue that you are seeing and have opened the following bug:
http://bugs.eclipse.org/411001
UPDATE
The fix for this issue has been checked into the EclipseLink 2.5.1 and 2.6.0 streams. You can get the fix in the corresponding nightly builds from the following link starting June 19, 2013:
http://www.eclipse.org/eclipselink/downloads/nightly.php

Resources