Strongly-Typed values in specflow scenario - specflow

Is there any way to use Strongly-Typed values in Examples table of the scenario? (or alternative solution)
I'd like to know if I made a typo in userType column already during the coding (not during running the test).
UPDATED
file.feature
Scenario Outline: Scenario123
Given Create new user of type "<userType>"
Examples:
| userType |
| PlatinumUser |
| CommonUser |
steps.cs
[Given(#"Create new user of type ""(.*)""")]
public void CreateNewUser(UserTypeEnum userType)
{
// some code like e.g.:
MyUser user = new MyUser(userType);
//...
}
enum UserTypeEnum { CommonUser, PlatinumUser, Spectre }

Looks like its a StepArgumentTransformation that you are after?
https://github.com/techtalk/SpecFlow/wiki/Step-Argument-Conversions
Used somehow along these lines:
[Binding]
public class Transforms
{
[StepArgumentTransformation]
public UserTypeEnum UserTypeTransform(string UserType)
{
// return the string converted into the required Enum
}
}
The step binding will see that it requires a UserTypeEnum as a parameter so it will search for all the available Step Argument Transformations within any classes with the Binding attribute and use this method to perform the conversion.

Specflow supports accepting strongly typed enum values.
Though, the scenario sends it as text (case insensitive).
example:
Scenario: Some enum test
When I send enum "Second"
Then I get the second enum
public enum ChosenOption
{
First,
Second,
Third,
}
[When(#"I send enum ""(.*)""")]
public void WhenISendEnum(ChosenOption option)
{
_scenarioContext.Set(option, nameof(ChosenOption));
}
[Then(#"I get the second enum")]
public void ThenIGetTheSecondEnum()
{
var chosen = _scenarioContext.Get<ChosenOption>(nameof(ChosenOption));
chosen.Should().Be(ChosenOption.Second);
}

Related

Fitnesse Trim String data before comparison

I wanted to ask if there is a way to trim String data before comparing it with the data in the table. For example, if we have
|MyCompareClass|
|getString? |
|string1 |
And the result of getString() will be "string1 ". I want the comparison to be green and not Expected "string1".
I'm looking for a way to do it without modifying the MyCompareClass source code. Any ideas?
You can write a custom string compare operator class:
public class MyCustomCompare: CellOperator, CompareOperator<Cell> {
public bool CanCompare(TypedValue actual, Tree<Cell> expected) {
return actual.Type == typeof(string);
}
public bool Compare(TypedValue actual, Tree<Cell> expected) {
return actual.Value.ToString().Trim() == expected.Value.Text;
}
}
Then register your class with the Fitnesse configure fixture:
|configure|processor|add operator|MyCustomCompare|
You could put !-string1 -! in your cell. All other options I can think of involve code changes to either SUT or fixture.

Grails Controller Action Abstract Command Object Parameter

Is there any support for using abstract command objects in controller action parameters? Then depending on the given parameters in a JSON request it would select the correct command object?
For example something like:
class SomeController {
def someAction(BaseCommand cmd){
// cmd could be instance of ChildCommandOne or ChildCommandTwo
}
class BaseCommand {
String paramOne
}
class ChildCommandOne extends BaseCommand {
String paramTwo
}
class ChildCommandTwo extends BaseCommand {
String paramThree
}
}
As of now I've been using request.JSON to detect the passed in parameters and instantiate the correct Command object. Is that my only option to handle this sort of case?
EDIT :
To clarify the use case here. I have two domain models that share the same base class domain model and I'm modeling the inheritance in the database using the default table-per-hierarchy model.
In my case, one of the child domain models Model A requires a non-nullable String called body, that is a Text entry, while the other Model B requires a non-nullable String called directUrl. These represent announcements that can be made on the platform. Model A being a write in entry that contains the announcement body while Model B represents a link to a third party site that contains the actual announcement.
In these sort of scenarios I've traditionally put an if statement in the controller action that determines which related command object to instantiate but I am hoping for a cleaner method.
It won't work this way. Grails needs a concrete class (with default public constructor) to bind request params to a command object instance. Therefore this class is to be defined explicitely as action's argument.
I guess you will have to call binding manually depending on what map contains.
See RootModel.from(Map map). In your case Map would be params from Controller
import static com.google.common.base.Preconditions.checkNotNull
import spock.lang.Specification
import spock.lang.Unroll
class CommandHierarchySpec extends Specification {
#Unroll
def "should create object of type #type for map: #map"() {
when:
def modelObj = RootModel.from(map)
then:
modelObj.class == type
where:
type | map
ModelA | [body: 'someBody', test: 'test']
ModelB | [directUrl: 'directUrl', test: 'test']
}
def "should throw ISE when map does not contain neither body nor url"() {
when:
RootModel.from(a: 'b')
then:
thrown(IllegalStateException)
}
}
abstract class RootModel {
static RootModel from(Map map) {
checkNotNull(map, "Parameter map mustn't be null")
RootModel rootModel
if (map.body) {
rootModel = new ModelA()
} else if (map.directUrl) {
rootModel = new ModelB()
} else {
throw new IllegalStateException("Cannot determine command type for map: $map")
}
map.findAll { key, value -> rootModel.hasProperty(key) }
.each {
rootModel.setProperty(it.key, it.value)
}
rootModel
}
}
class ModelA extends RootModel {
String body
}
class ModelB extends RootModel {
String directUrl
}

Cannot use enum in repository query (neo4j/Spring Data)

I'm having a problem querying based on an Enum property of my NodeEntity.
The NodeEntity in question is defined:
#NodeEntity(label = "Entity")
public class MyEntity {
#GraphId
private Long internalId;
....
private State state;
#Transient
public enum State {
STATEONE, STATETWO, STATETHREE
}
....
It saves without a problem, the state Enum represented perfectly, and I can query using other properties (Strings) with no problem at all. However the problem is the following query in a repository:
#Query("MATCH (entity:Entity {state:{0}})" +
"RETURN entity")
List<MyEntity> findByState(MyEntity.State state)
i.e. find all entities with the given state.
There's no exception, however using this simply returns a List of 0 Entities.
I've tried all kinds of variations on this, using a WHERE clause for example, with no luck.
The Entities are persisted properly, using findAll() in the same test returns the expected List of Entities with their states exactly as I would expect.
Any thoughts?
Not quite sure what the value #Transient adds to the enum. It is anyway not persistable as a node or relationship in Neo4j. It is sufficient to define the field as one that should persist with
private State state;
and leave off the #Transient annotation from the enum.
With it, SDN ignores the field sent to the derived query.
However, if you have a good reason to mark the enum #Transient, please do share it and we'll re-visit this case.
There is a general problems using spring data rest interface to search on enum fields. Just using the enum-to-string converter cannot work for search where you want to find if the value is IN a collection of values:
public interface AppointmentRepository extends Neo4jRepository<Appointment, Long> {
Page<Appointment> findByDayOfWeekIn(#Param("days") List<DayOfWeek> days, Pageable pageable);
}
The above does not work out of the box because neo4j will try to convert a List to your property type: DayOfWeek
In order to work around this I needed a custom converter that handles both requests providing collection of values (the search) and single values (the normal read and write entity):
#SuppressWarnings({ "unchecked", "rawtypes" })
public abstract class SearchQueryEnumConverter<T extends Enum> {
private Class<T> enumType;
public SearchQueryEnumConverter() {
enumType = (Class<T>) ((ParameterizedType) this.getClass()).getActualTypeArguments();
}
public Object toGraphProperty(Object value) {
if (Collection.class.isAssignableFrom(value.getClass())) {
List<T> values = (List<T>) value;
return values.stream().map(Enum::name).collect(Collectors.toList());
}
return ((Enum) value).name();
}
public Object toEntityAttribute(Object value) {
if (Collection.class.isAssignableFrom(value.getClass())) {
List<String> values = (List<String>) value;
return values.stream().map(v -> (T) T.valueOf(enumType, v)).collect(Collectors.toList());
}
return (T) T.valueOf(enumType, value.toString());
}
}
The abstract converter can be reified by all enums, and used as parameter of the #Convert annotation:
public enum EnumType {
VALUE_A, VALUE_B;
public static class Converter extends SearchQueryEnumConverter<EnumType> implements AttributeConverter {
}
}
#NodeEntity
public Entity {
#Property
#Convert(EnumType.Converter.class)
EnumType type;
}

SYMFONY FORM ChoiceType, multiple=>true. How to by pass the need to implement Data Transformers

In a SYMFONY FORM (ORM is not use (PDO is used for DB query instead)).
I have a class MyEntityType in which the buildForm function has:
$builder->add('my_attribute',ChoiceType::class,array(
'choices'=>$listForMyAttribute,
'multiple'=>'true',
'attr'=>array('data-native-menu'=>'false'),
'label'=>'Multiple Select on my attribute'
));
My attribute is an array of an entity named MyEntity which has:
/**
* #Assert\NotBlank()
*/
private $myAttribute;
With a getter and a setter for that variable $myAttribute.
When I submit the form in the Controller, it doesn't pass the validation check and logs this error:
Unable to reverse value for property path "myAttribute" : Could not find all matching choices for the given values.
When I start to look for solution around this error message, it leads to something named "How to Use Data Transformers" in SYMFONY Cookbook; And it seems a solution would involve to create new Class and write a lot of code for something that one should be able to by-pass in a much straight forward way.
Does anyone have an idea?
My problem was that my array $listForMyAttribute was defined in the buildForm() function and its definition was relying on some conditional.
The conditional to make the array were met when this one was displayed for the first time.
After pushing the submit button, the buildForm was regenerated in the Controller, this second time, the condition were not met to make the array $listForMyAttribute as it was on the first display. Hence the program was throwing a "contraint not met error" because the value submited for that field could not be find.
Today I face exactly the same problem. Solution is simple as 1-2-3.
1) Create utility dummy class DoNotTransformChoices
<?php
namespace AppBundle\DataTransformer;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
class DoNotTransformChoices implements ChoiceListInterface
{
public function getChoices() { return []; }
public function getValues() { return []; }
public function getPreferredViews() { return []; }
public function getRemainingViews() { return []; }
public function getChoicesForValues(array $values) { return $values; }
public function getValuesForChoices(array $choices) { return $choices; }
public function getIndicesForChoices(array $choices) { return $choices; }
public function getIndicesForValues(array $values) { return $values; }
}
2) Add to your field the following additional option:
...
'choice_list' => new DoNotTransformChoices,
...
3) Congratulations!

Grails - CreateCriteria to Retrieve any entry that contains any element in query

Given I have this domain:
class Game {
Set<GameType> gameType
String name
}
And this enum:
enum Gametype {
RHYTHM, ADVENTURE, PUZZLE, RPG, HORROR, FIGHTING, MOBA, MMO
}
I need to retrieve a list of games that contains at least one of the game types indicated in the query. I tried using this code:
def retrieveGamesThatMayBeUnderGameTypes( List<GameType> listOfGameTypes) {
return Game.createCriteria().list(){
'in'("gameType", listOfGameTypes)
}
}
However, it returns a NullPointerException. Any ideas?
Just make sure your enum (Gametype) has a field called id. Something like:
enum Gametype {
RHYTHM('RHYTHM'),
ADVENTURE('ADVENTURE'),
....
String id
Gametype(String id) {
this.id = id
}
}
See this answer for more: Grails Enum Mapping

Resources