Skip to content
Dmitrii Demin edited this page Feb 13, 2018 · 74 revisions

Purpose and features

This library helps to route yours parallel tests to different environments and allows to use personal environment settings for each parallel test (java thread)

Features

  • Routing of test entity (test thread) to appropriate environment by required environment name
  • Assigning of current environment object (for current test) to current java thread
  • Storing of personal properties and path to personal folder in each environment object
  • Routing/balancing by priority (higher int value - lower priority)
  • Routing of multiple threads to one environment (configurable)
  • Waiting of environments availability with timeout (configurable)
  • Executing of only one thread per environment for some marked entities (other entities are waiting)
  • Assigning some environment to entities that don't have environment (default environment)
  • Overriding of environment for all entities (forced environment)
  • CUCUMBER: Parallel tests based on features OR scenarios (via TestNG)
  • CUCUMBER: Support of Logback MDC discriminator via test entity's name (see logback.xml & AbstractCucumberTest.class)
  • CUCUMBER: Support of tests running via CLI class (applicable to Cucumber-java IDEA plugin) with Google Guice and XStreamConverters support (see System Properties below)

Installation (Gradle + TestNG)

  1. Go to page on Maven Central
  2. Choose your dependency management tool and add appropriate code to your configuration
  3. Be sure that test task has testNG() section with setParallel("instances")

System Properties

Global

  1. router.envs.dir - relative path from src/test/resources. This folder will be scan and all subdirectories (non-recursive) will be transformed to 'environments'. Default - environments
  2. router.envs.default - if defined then will be used as required env. name for test entity if no req. env. will be provided to constructor. Otherwise, name 'any' will be used, that means this test entity will be routed to any available environment. Default - null
  3. router.envs.forced - if defined then will be used as required env. name for each test entity in any case if defined. Default - null
  4. router.threadsPerEnv - max slots for parallel test threads for each environment. Default - 1
  5. router.lock.timeout - timeout (ms) for waiting of succesful environment lock. Default - 60000

For Cucumber-JVM

  1. cuke.tags - same as Cucumber-jvm Wiki (tags), but instead of multiple '--tags' args you must use ';' delimiter. Example: '-Dcuke.tags="@tagA or not @tagC;@tagB"'
  2. cuke.converters - ',' delimited list of full classes (OR packages) names that contains implementation of ConverterMatcher (see XStreamConverters). Will be added to Cucumber runtime when RouterCucumberCli will be used
  3. cuke.guice.modules - ',' delimited list of full classes (OR packages) names that contains implementation of Module (see Guice modules). Will be injected when RouterCucumberCli will be used

Cucumber-JVM + TestNG

Usage

For example - please look at com.github.ddemin.envrouter.demo.CukeFeatureBasedTests or com.github.ddemin.envrouter.demo.CukeScenarioBasedTests and their superclasses

  1. Your class must extends AbstractCucumberScenarioTest or AbstractCucumberFeatureTest (parallelism via scenarios or features)
  2. Your class must be annotated by @CucumberOptions
  3. Your class must have default constructor with annotation @Factory(dataProvider = "routerDataProvider")
  4. Your class must have some public method with annotation @Test that calls 'super.runCucumberEntity();'
  5. Your class must implements 'protected void processFailedLocking(EnvironmentLock lock);'
  6. For access to environment directory path and properties (env props. + system props.) you should call 'EnvironmentsUtils.getCurrent();' or 'EnvironmentsUtils.getCurrent().getProperties();'. See com.github.ddemin.envrouter.demo.step.StepDefs class for example

Running

  • Just call 'test' gradle task with system properties (starts with -D) that you want (see 'Installation (Gradle + TestNG)' and 'System Properties' paragraphs above)

Debugging (via IDEA)

  • Install latests Cucumber for Java plugin
  • Go to "Run / Edit Configurations / Defaults / Cucumber java"
  • Set "Main class" = com.github.ddemin.envrouter.cucumber2.RouterCucumberCli
  • Set "Glue" (path to package that contains step definitions classes) = com.myproject.highlevelpackage
  • Set "VM Options" = -Drouter.envs.forced=mir_ddemin_standalone -Dcuke.converters=packagepath.to.first.convertermatcher.Implementation,packagepath.to.second.convertermatcher.Implementation, -Dcuke.guice.modules=packagepath.to.first.implementation.ofguicemodule.Class,packagepath.to.second.implementation.ofguicemodule.Class -Dother.properties
  • Go to feature file, right-mouse click on scenario or feature, select Run or Debug and click on it

Tags

  1. @Priority1 means that this feature/scenario will have priority = 1. Lowest integer value means highest priorty.
  2. @EnvTest1 means that this feature/scenario will be routed to environment with name 'test1'. If tag missed then default environment will be used, otherwise - any environment will be used (feature will be routed to any available defined environment) OR default env will be used if property router.envs.default is defined. Also property router.envs.forced will override any values from @Env tag for all features/scenarios
  3. @SingleThread means that this feature/scenario will hard-lock of required environment - only one (this) test-thread will be executed on target environment (other threads that require same env. will be waiting). Entities with this tag will have lower priority than entities with same @Priority tag
  4. Feel free to use cucumber-jvm tags functionality for tests filtering (see System Properties paragraph & cuke.tags property description)

Demo (Cucumber-JVM + TestNG)

  1. Checkout this project
  2. Execute 'gradlew demoViaFeatures' or 'gradlew demoViaScenarios' in project root. Then execute 'gradlew allureReport allureServe' that will open Allure Report in default web browser.

Explanation (based on demoViaFeatures task)

  1. All directories (non-recursive) inside src/test/resources/environments mean 'defined environments' and will be saved as Environment objects
  2. Each Environment object will read all properties from .properties files from personal folder and enrich them with System properties
  3. Also each Environment object will be enriched with properties that store in .properties files in src/test/resources/environments (non-recursive)
  4. All feature files that can be found by using data from @CucumberOptions annotation will be transformed to special wrapper. This wrapper also contains feature priority (from @Priority tag), required environment name (from @Env tag) and requirement of hard-locking (one thread per env, from @SingleThread tag)
  5. TestNG will create CukeTests objects as much as objects will returned by routerDataProvider (see AbstractCucumberTest)
  6. Each TestNG test will try to lock environment and find appropriate feature for testing and pull it from queue
  7. Each java thread that will execute test will have access to environment's personal properties and path to personal directory via EnvironmentsUtils#getCurrent method
  8. Environment will be released after testing of 'feature' file

Classes interaction scheme (based on TestNG & AbstractCucumberFeatureTest class)

Click to expand (use zoom)