es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo ejecutar características de Cucumber múltiples veces con diferentes códigos bajo prueba?

La versión resumida:
¿Cómo hago el @RunWith(Parameterized::class) de JUnit con las características de Cucumber?

Tengo archivos de características que me gustan. Quiero ejecutar exactamente los mismos rasgos varias veces, pero cambiar “el entorno” para que el código @Before en mis step-defs sea ligeramente diferente. Tengo algunas implementaciones diferentes de algún código de prueba y quiero asegurarme de que todos funcionen. Así que tiene que ser parte del pipeline de CI. No una cosa de cmd-line manual.

Lo que quiero cambiar entre ejecuciones no tiene ningún significado semántico para los archivos de escenarios/rasgos, por lo que preferiría no alterarlos radicalmente ni duplicarlos.

Estoy usando el stock java/kotlin y gradle junit. No hay spring, no hay webUI.

Configuré múltiples ganchos junit que apuntan a los mismos rasgos, lo que funciona para ejecutar los rasgos varias veces. Pero no puedo averiguar cómo obtener información desde el gancho hasta los step-defs.

— Actualización —

Aquí está el código que tengo para enchufar las pruebas de pepino en junit:

@RunWith(Cucumber::class)
@CucumberOptions(
features = [“src/test/resources/hellocucumber/”],
)
class FirstRun

@RunWith(Cucumber::class)
@CucumberOptions(
features = [“src/test/resources/hellocucumber/”],
)
class SecondRun

Esto realmente ejecuta las pruebas dos veces, que es lo que quiero.

Pero en mis step-defs, la sección @Before donde configuro el código de prueba, ¿cómo puedo saber si es la primera ejecución o la segunda? No puedo encontrar una forma de obtener ningún dato de estos stubs a los step-defs.

¿Tal vez no es la forma de hacer esto?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para utilizar @RunWith(Parameterized::class) con características de Cucumber, puedes crear un corredor JUnit personalizado que extienda Parameterized y anule el método parameters() para devolver una colección de objetos ScenarioOutlineWrapper. Cada ScenarioOutlineWrapper representará una sola ejecución del archivo de características con diferentes valores de parámetros.

    La clase ScenarioOutlineWrapper puede contener campos que representen los parámetros que se van a variar entre ejecuciones, y estos campos se pueden definir en el constructor de la clase.

    En el método @Before de tus definiciones de pasos, puedes acceder a los campos del objeto ScenarioOutlineWrapper que corresponde a la ejecución de prueba actual. Puedes usar estos campos para configurar adecuadamente tu código de prueba.

    Aquí hay un ejemplo de una clase de corredor personalizada:

    @RunWith(CustomParameterizedCucumber.class)
    @CucumberOptions(
        features = {"src/test/resources/my.feature"},
        glue = {"com.example.steps"})
    public class MyTest {
    
        @CustomParameterizedCucumber.Parameters
        public static Collection<object[]> data() {
            return Arrays.asList(new Object[][]{
                    {"env1"},
                    {"env2"},
                    {"env3"}
            });
        }
    }
    

    Y la clase CustomParameterizedCucumber:

    public class CustomParameterizedCucumber extends Parameterized implements CucumberOptionsProvider {
        private final List<runner> runners;
    
        public CustomParameterizedCucumber(Class<?> testClass) throws Throwable {
            super(testClass);
            runners = buildRunners(testClass);
        }
    
        @Override
        public List<runner> getAdditionalChildren(CucumberOptions cucumberOptions) {
            return runners;
        }
    
        private List<runner> buildRunners(Class<?> testClass) throws Throwable {
            List<runner> runners = new ArrayList<>();
            for (Object[] parameters : getParametersList(testClass)) {
                runners.add(new CustomScenarioOutlineRunner(testClass, parameters));
            }
            return runners;
        }
    
        private List<object[]> getParametersList(Class<?> testClass) throws Throwable {
            Collection<object[]> rawParameters = getParameters(testClass);
            List<object[]> parametersList = new ArrayList<>(rawParameters.size());
            for (Object[] params : rawParameters) {
                parametersList.add(new Object[]{new ScenarioOutlineWrapper(params)});
            }
            return parametersList;
        }
    
        static class CustomScenarioOutlineRunner extends ScenarioOutlineRunner {
            private final ScenarioOutlineWrapper scenarioOutlineWrapper;
    
            CustomScenarioOutlineRunner(Class<?> clazz, Object[] params) throws InitializationError {
                super(clazz, params);
                this.scenarioOutlineWrapper = (ScenarioOutlineWrapper) params[0];
            }
    
            @Override
            public Description getDescription() {
                Description description = super.getDescription();
                description.addChild(getCustomizedDescription());
                return description;
            }
    
            private Description getCustomizedDescription() {
                return Description.createTestDescription(
                    getTestClass().getJavaClass(),
                    getDescription().getDisplayName(),
                    scenarioOutlineWrapper.toString());
            }
    
            @Override
            protected void runChild(StepDefinitionMatch stepDefinitionMatch, RunNotifier notifier) {
                scenarioOutlineWrapper.setUp();
                super.runChild(stepDefinitionMatch, notifier);
                scenarioOutlineWrapper.tearDown();
            }
        }
    
        static class ScenarioOutlineWrapper {
            private final Object[] params;
            private String environment;
    
            public ScenarioOutlineWrapper(Object[] params) {
                this.params = params;
            }
    
            public void setUp() {
                environment = (String) params[0];
                // configure code under test based on environment
            }
    
            public void tearDown() {
                // clean up after test run
            }
    
            @Override
            public String toString() {
                return "Environment: " + environment;
            }
        }
    }
    

    En este ejemplo, la clase MyTest está parametrizada con el entorno y CustomScenarioOutlineRunner envuelve cada esquema de escenario en un objeto ScenarioOutlineWrapper que contiene el entorno que se va a utilizar en esa ejecución de prueba.

    En el método getDescription(), agregamos el objeto ScenarioOutlineWrapper a la descripción de la prueba para que podamos ver fácilmente qué entorno se está utilizando en cada ejecución.

    En el método runChild(), llamamos a setUp() y tearDown() en el objeto ScenarioOutlineWrapper para configurar y limpiar después de cada ejecución de prueba.

    Con esta configuración, puedes ejecutar la prueba usando gradle test, y automáticamente ejecutará el archivo de características varias veces con diferentes parámetros.</object[]></object[]></object[]></object[]>

Comments are closed.