valor salida referencia por paso parámetros parametros parametro objeto ejemplos ejemplo copiar como java cucumber cucumber-jvm

salida - paso de parametros en java ejemplo



Buena práctica para pasar variables entre pasos de pepino-jvm. (7)

Para pasar variables entre pasos ahora estoy haciendo algo como el ejemplo de la siguiente manera:

Feature: Demo Scenario: Create user Given User creation form management When Create user with name "TEST" Then User is created successfully

Clase de Java con definiciones de pasos:

public class CreateUserSteps { private String userName; @Given("^User creation form management$") public void User_creation_form_management() throws Throwable { // ... } @When("^Create user with name /"([^/"]*)/"$") public void Create_user_with_name(String userName) throws Throwable { //... this.userName = userName; } @Then("^User is created successfully$") public void User_is_created_successfully() throws Throwable { // Assert if exists an user with name equals to this.userName }

Mi pregunta es si esta es una buena práctica para compartir información entre pasos. O sería mejor definir la característica como:

Then User with name "TEST" is created successfully

Soy nuevo con cucumber-jvm, lo siento si es una pregunta sin cerebro.

Cualquier ayuda sería apreciada. Gracias


A mi manera: defino un Scenario-Scope personalizado con cada nuevo escenario, habrá un nuevo contexto.

Feature @Dummy Scenario: zweites Scenario When Eins Then Zwei

1: usar primavera

<properties> <cucumber.version>1.2.5</cucumber.version> <junit.version>4.12</junit.version> </properties> <!-- cucumber section --> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-java</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-spring</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <!-- end cucumber section --> <!-- spring-stuff --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.4.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.4.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.4.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.4.RELEASE</version> <scope>test</scope> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.4.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>2.4.0.RELEASE</version> <scope>test</scope> </dependency>

2: construir clase de alcance personalizado

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope(scopeName="scenario") public class ScenarioContext { public Scenario getScenario() { return scenario; } public void setScenario(Scenario scenario) { this.scenario = scenario; } public String shareMe; }

3: uso en stepdef

@ContextConfiguration(classes = { CucumberConfiguration.class }) public class StepdefsAuskunft { private static Logger logger = Logger.getLogger(StepdefsAuskunft.class.getName()); @Autowired private ApplicationContext applicationContext; // Inject service here : The impl-class need @Primary @Service // @Autowired // IAuskunftservice auskunftservice; public ScenarioContext getScenarioContext() { return (ScenarioContext) applicationContext.getBean(ScenarioContext.class); } @Before public void before(Scenario scenario) { ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) applicationContext).getBeanFactory(); beanFactory.registerScope("scenario", new ScenarioScope()); ScenarioContext context = applicationContext.getBean(ScenarioContext.class); context.setScenario(scenario); logger.fine("Context für Scenario " + scenario.getName() + " erzeugt"); } @After public void after(Scenario scenario) { ScenarioContext context = applicationContext.getBean(ScenarioContext.class); logger.fine("Context für Scenario " + scenario.getName() + " gelöscht"); } @When("^Eins$") public void eins() throws Throwable { System.out.println(getScenarioContext().getScenario().getName()); getScenarioContext().shareMe = "demo" // you can save servicecall here } @Then("^Zwei$") public void zwei() throws Throwable { System.out.println(getScenarioContext().getScenario().getName()); System.out.println(getScenarioContext().shareMe); // you can use last service call here } @Configuration @ComponentScan(basePackages = "i.am.the.greatest.company.cucumber") public class CucumberConfiguration { }

la clase de alcance

import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; public class ScenarioScope implements Scope { private Map<String, Object> objectMap = Collections.synchronizedMap(new HashMap<String, Object>()); /** (non-Javadoc) * @see org.springframework.beans.factory.config.Scope#get(java.lang.String, org.springframework.beans.factory.ObjectFactory) */ public Object get(String name, ObjectFactory<?> objectFactory) { if (!objectMap.containsKey(name)) { objectMap.put(name, objectFactory.getObject()); } return objectMap.get(name); } /** (non-Javadoc) * @see org.springframework.beans.factory.config.Scope#remove(java.lang.String) */ public Object remove(String name) { return objectMap.remove(name); } /** (non-Javadoc) * @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String, java.lang.Runnable) */ public void registerDestructionCallback(String name, Runnable callback) { // do nothing } /** (non-Javadoc) * @see org.springframework.beans.factory.config.Scope#resolveContextualObject(java.lang.String) */ public Object resolveContextualObject(String key) { return null; } /** (non-Javadoc) * @see org.springframework.beans.factory.config.Scope#getConversationId() */ public String getConversationId() { return "VolatileScope"; } /** * vaporize the beans */ public void vaporize() { objectMap.clear(); } }


En Pure Java, solo uso un objeto Singleton que se crea una vez y se borra después de las pruebas.

public class TestData_Singleton { private static TestData_Singleton myself = new TestData_Singleton(); private TestData_Singleton(){ } public static TestData_Singleton getInstance(){ if(myself == null){ myself = new TestData_Singleton(); } return myself; } public void ClearTestData(){ myself = new TestData_Singleton(); }


Está bien compartir datos entre los pasos definidos dentro de una clase usando una variable de instancia. Si necesita compartir datos entre los pasos en diferentes clases, debe mirar las integraciones DI (PicoContainer es el más simple).

En el ejemplo que muestra, me gustaría preguntar si es necesario mostrar "PRUEBA" en el escenario. El hecho de que el usuario se llame PRUEBA es un detalle incidental y hace que el escenario sea menos legible. ¿Por qué no generar un nombre aleatorio (o algo duro) en Create_user_with_name ()?


Otra opción es utilizar el almacenamiento ThreadLocal. Crea un mapa de contexto y agrégalos al mapa. Cucumber JVM ejecuta todos los pasos en el mismo subproceso y usted tiene acceso a todos estos pasos. Para hacerlo más fácil, puede crear una instancia del almacenamiento antes del enganche y borrar después del enganche.


Para compartir puntos en común entre los pasos, necesitas usar un World . En Java no es tan claro como en Ruby.

Citando al creador del pepino.

El propósito de un "Mundo" es doble:

1) Aislar el estado entre escenarios.

2) Comparta datos entre definiciones de pasos y enlaces dentro de un escenario.

Cómo se implementa esto es específico del lenguaje. Por ejemplo, en ruby, la self variable implícita dentro de una definición de paso apunta al objeto Mundo del escenario actual. Esta es una instancia de Object por defecto, pero puede ser lo que quieras si usas el gancho del mundo.

En Java, tienes muchos objetos del mundo (posiblemente conectados).

El equivalente de World in Cucumber-Java es todos los objetos con anotaciones hook o stepdef . En otras palabras, cualquier clase con métodos anotados con @Before, @After, @Given, etc., se instanciará exactamente una vez para cada escenario.

Esto logra el primer objetivo. Para lograr el segundo objetivo tienes dos enfoques:

a) Use una sola clase para todas sus definiciones de pasos y enlaces

b) Use varias clases divididas por responsabilidad [1] y use la inyección de dependencia [2] para conectarlas entre sí.

La opción a) se rompe rápidamente porque su código de definición de paso se convierte en un desastre. Es por eso que la gente tiende a usar b).

[1] https://github.com/cucumber/cucumber/wiki/Step-Organization

[2] PicoContainer, Spring, Guice, Weld, OpenEJB, Needle

Los módulos de inyección de dependencia disponibles son:

  • pepino-picocontainer
  • pepino-guice
  • pepino-openejb
  • pepino de primavera
  • soldadura de pepino
  • aguja de pepino

Publicación original aquí https://groups.google.com/forum/#!topic/cukes/8ugcVreXP0Y .

Espero que esto ayude.



Yo diría que hay razones para compartir información entre pasos, pero no creo que ese sea el caso en este escenario. Si propaga el nombre de usuario a través de los pasos de prueba, entonces no está claro de qué se trata. Creo que es mejor decir específicamente en el escenario lo que se espera. Probablemente haría algo como esto:

Feature: Demo Scenario: Create user Given User creation form management When Create user with name "TEST" Then A user named "TEST" has been created

Entonces, sus pasos de prueba reales podrían verse algo como:

@When("^Create user with name /"([^/"]*)/"$") public void Create_user_with_name(String userName) throws Throwable { userService.createUser(userName); } @Then("^A user named /"([^/"]*)/" has been created$") public void User_is_created_successfully(String userName) throws Throwable { assertNotNull(userService.getUser(userName)); }