CodeceptJS tiene dos motores para ejecutar pruebas en paralelo:

  • run-workers – que genera Trabajador de NodeJS(abre una nueva ventana) en un hilo. Las pruebas se dividen por escenarios, los escenarios son mixed entre grupos, cada trabajador ejecuta pruebas desde su propio grupo.
  • run-multiple – que genera un subproceso con CodeceptJS. Las pruebas se dividen por archivos y se configuran en codecept.conf.js.

Los trabajadores son más rápidos y sencillos de comenzar, mientras run-multiple requiere configuración adicional y se puede utilizar para ejecutar pruebas en diferentes navegadores a la vez.

Ejecución paralela por parte de los trabajadores

Es fácil ejecutar pruebas en paralelo si tiene muchas pruebas y núcleos de CPU libres. Simplemente ejecute sus pruebas usando run-workers comando que especifica el número de trabajadores a generar:

npx codeceptjs run-workers 2

ℹ Los trabajadores requieren NodeJS> = 11.7

Este comando es similar a runSin embargo, la salida de pasos no se puede mostrar en el modo de trabajo, ya que es imposible sincronizar la salida de pasos de diferentes procesos.

Cada trabajador hace girar una instancia de CodeceptJS, ejecuta un grupo de pruebas y envía un informe al proceso principal.

De forma predeterminada, las pruebas se asignan una a una a los trabajadores disponibles, lo que puede llevar a la ejecución múltiple de BeforeSuite(). Usa la opción --suites asignar las suites una a una a los trabajadores.

npx codeceptjs run-workers --suites 2

Ejecución paralela personalizada

Para obtener un control total de la paralelización, cree un script de ejecución personalizado que se adapte a sus necesidades. De esta forma se puede configurar qué pruebas se casan, cómo se forman los grupos y con qué configuración se ejecuta cada trabajador.

Comience con la creación de un archivo bin/parallel.js.

En MacOS / Linux, ejecute los siguientes comandos:

mkdir bin
touch bin/parallel.js
chmod +x bin/parallel.js

El nombre de archivo o directorio se puede personalizar. Estás creando tu propio corredor personalizado, así que toma este párrafo como ejemplo.

Cree un marcador de posición en el archivo:

#!/usr/bin/env node
const  Workers, event  = require('codeceptjs');
// here will go magic

Ahora veamos cómo actualizar este archivo para diferentes modos de paralelización:

Ejemplo: ejecución de pruebas en 2 navegadores en 4 subprocesos

const workerConfig = 
  testConfig: './test/data/sandbox/codecept.customworker.js',
;

// don't initialize workers in constructor
const workers = new Workers(null, workerConfig);
// split tests by suites in 2 groups
const testGroups = workers.createGroupsOfSuites(2);

const browsers = ['firefox', 'chrome'];

const configs = browsers.map(browser => 
  return helpers: 
    WebDriver:  browser 
  
);

for (const config of configs) 
  for (group of testGroups) 
    const worker = workers.spawn();
    worker.addTests(group);
    worker.addConfig(config);
  


// Listen events for failed test
workers.on(event.test.failed, (failedTest) => 
  console.log('Failed : ', failedTest.title);
);

// Listen events for passed test
workers.on(event.test.passed, (successTest) => 
  console.log('Passed : ', successTest.title);
);

// test run status will also be available in event
workers.on(event.all.result, () => 
  // Use printResults() to display result with standard style
  workers.printResults();
);

// run workers as async function
runWorkers();

async function runWorkers() 
  try 
    // run bootstrapAll
    await workers.bootstrapAll();
    // run tests
    await workers.run();
   finally 
    // run teardown All
    await workers.teardownAll();
  

Dentro event.all.result puede obtener los resultados de las pruebas de todos los trabajadores, por lo que puede personalizar el informe:

workers.on(event.all.result, (status, completedTests, workerStats) => 
  // print output
  console.log('Test status : ', status ? 'Passes' : 'Failed ');

  // print stats
  console.log(`Total tests : $workerStats.tests`);
  console.log(`Passed tests : $workerStats.passes`);
  console.log(`Failed test tests : $workerStats.failures`);

  // If you don't want to listen for failed and passed test separately, use completedTests object
  for (const test of Object.values(completedTests)) 
    console.log(`Test status: $test.err===null, `, `Test : $test.title`);
  

Ejemplo: ejecución de pruebas divididas por una función personalizada

Si desea que sus pruebas se dividan según sus necesidades, este método es adecuado para usted. Por ejemplo: si tiene 4 archivos de prueba de ejecución prolongada y 4 archivos de prueba normales, es posible que las 4 pruebas terminen en el mismo hilo de trabajo. Para estos casos, la función personalizada será útil.

/*
 Define a function to split your tests.

 function should return an array with this format [[file1, file2], [file3], ...]

 where file1 and file2 will run in a worker thread and file3 will run in a worker thread
*/
const splitTests = () => 
  const files = [
    ['./test/data/sandbox/guthub_test.js', './test/data/sandbox/devto_test.js'],
    ['./test/data/sandbox/longrunnig_test.js']
  ];

  return files;


const workerConfig = 
  testConfig: './test/data/sandbox/codecept.customworker.js',
  by: splitTests
;

// don't initialize workers in constructor
const customWorkers = new Workers(null,  workerConfig);

customWorkers.run();

// You can use event listeners similar to above example.
customWorkers.on(event.all.result, () => 
  workers.printResults();
);

Compartir datos entre trabajadores

Los trabajadores de NodeJS pueden comunicarse entre sí a través del sistema de mensajería. Puede suceder que desee pasar algunos datos de uno de los trabajadores a otro. Por ejemplo, es posible que desee compartir las credenciales de usuario en todas las pruebas. Los datos se adjuntarán a un contenedor.

Sin embargo, no puede acceder a datos no inicializados desde un contenedor, por lo que para comenzar, primero debe inicializar los datos. Dentro bootstrap función de la configuración ejecutamos el share funcionar con local: true para inicializar el valor localmente:

// inside codecept.conf.js
exports.config = 
  bootstrap() 
    // append empty userData to container for current worker
    share( userData: false ,  local: true );
  

Ahora cada trabajador tiene userData dentro de un contenedor. Sin embargo, está vacío. Cuando obtiene datos reales en una de las pruebas, puede pasar estos datos a través de las pruebas. Usar inject función para acceder a los datos dentro de un contenedor:

// get current value of userData
let  userData  = inject();
// if userData is still empty - update it
if (!userData) 
  userData =  name: 'user', password: '123456' ;
  // now new userData will be shared accross all workers
  share(userData);