Test Automation: Maven Profiles and Parallelization in Azure Pipelines Using IaaS
When it comes to test automation, configuring parallel threads can become challenging. This article helps those who are looking to automate their QA and DevOps needs.
Join the DZone community and get the full member experience.
Join For FreeWhen it comes to Test Automation, configuring parallel threads can become challenging especially when logins are involved. It's more of a challenge for the UI/ Selenium test to run batches in a separate thread on Azure pipelines with separate credential sets.
Solution Overview: Create test suites using tags for the cucumber framework. Create profiles for login credentials and environments to run on. Compile the build with a test suite, login credentials, and environment to run on. This approach can be used for other types of test suits as well such as Junit.
Framework Configuration: Most frameworks use config.properties files to compile the desired build. Maven has provides some really simple ways to configure the build using build profiles. This helps generate a specific config file for each build using the command line.
STEP 1:
Properties PLugin in POM.XML
In your POM.XML file add the below plugin. Notice the file name in the example below 'properties-from-pom' which will be generated in your output or target folder when the goal 'mvn compile' is run.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>write-project-properties</goal>
</goals>
<configuration>
<outputFile>${project.build.outputDirectory}/properties-from-pom.properties</outputFile>
</configuration>
</execution>
</executions>
</plugin>
STEP 2:
Adding Properties in POM.XML
Now we can start adding the project properties to the POM.XML file. You can migrate the properties used in your config.properties file as shown below. You can create properties with custom names to be relevant to your needs. All these properties will be loaded in the properties-from-pom.xml file when the 'mvn compile' goal is run.
<properties>
<!-- PROJECT CONFIGURATION :-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ApplicationName>Name of the Application goes here</ApplicationName>
<!-- Login CREDENTIALS DEFAULT : -->
<username>please choose a username from maven profiles</username>
<!--Either place the username and password in these or leave them blank as they will be overloaded by the profiles-->
<!You will see below.-->
<password>please choose a password from maven profiles</password>
<!--Environment Configuration-->
<environment>please choose a environment by compiling using mvn compile -P{environment name} from maven profiles</environment>
<!-- same applies to the environment to run on-->
<!-- BROWSER CONFIGURATION : Unaffected by profiles-->
<browser>chrome</browser>
<!-- BROWSERSTACK CONFIGURATION -->
<BrowserStackEnabled>false</BrowserStackEnabled>
<browserstackBrowserName>chrome</browserstackBrowserName>
<!-- ENVIRONMENT URL -->
<DEV_URL>place your URLS to point here</DEV_URL>
<TEST_URL>place your URLS to point here</TEST_URL>
<UAT_URL>place your URLS to point here</UAT_URL>
<PP_URL>place your URLS to point here</PP_URL>
<PRODUCTION_URL>place your URLS to point here</PRODUCTION_URL>
<!-- WAITS AND TIMEOUTS -->
<wd_implicitWait>30</wd_implicitWait>
<wd_pageLoadTimeOut>20</wd_pageLoadTimeOut>
<speedController>0</speedController>
<!-- PATCHES -->
<patchNameIfAny>true</patchNameIfAny>
<!-- LOGGER CONFIGURATION -->
<logUser>${user.name}</logUser>
<log_switch>on</log_switch>
<!-- REPORT CONFIGURATION -->
<report_switch>on</report_switch>
<!-- SCREENSHOT -->
<screenshot_switch>on</screenshot_switch>
<!-- BROWSERSTACK CONFIGURATION -->
<BrowserStackURLHost>hub-cloud.browserstack.com/wd/hub</BrowserStackURLHost>
<BrowserStackUserName>BrowserStack User Name</BrowserStackUserName>
<BrowserStackKey>Browser Stack Authentication Key</BrowserStackKey>
<browserStackBrowserName>Chrome</browserStackBrowserName>
<browserStackBrowserVersion>85</browserStackBrowserVersion>
<browserStackOSname>Windows</browserStackOSname>
<browserStackOSVersion>10</browserStackOSVersion>
<browserStackSeleniumVersion>Selenium VersionNumber</browserStackSeleniumVersion>
</properties>
STEP 3:
Compiling builds using Maven Profiles:
<profiles>
<!-- ENVIRONMENT PROFILES -->
<profile>
<id>uat</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<environment>uat</environment>
<!-- NOTE : the property name has to match to the property declared in the previous step. -->
<!-- Previous Step : Loading Properties in POM -->
</properties>
</profile>
<profile>
<id>LoginSet1</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<username>username@domain.com</username>
<password>passwordValue</password>
</properties>
</profile>
</profiles>
How To Replace the Values in Properties-from-pom.xml by Using Profiles?
Compile the Maven project using mvn compile -P{profile-id} e.g: mvn compile -PLoginSet1 will replace the username and password in the properties-from-pom.xml file with the values from the profile.
This way you can run maven goals such as mvn compile test -PLoginSet1 -Puat which configures the build with values from the profiles. If you need to override any other property in the POM properties, it can be done with the -D switch. The mvn compile -DApplicationName="Sample Application". You can now create multiple builds in your Azure pipelines using these profiles.
STEP 4:
IaaS Infrastructure as a Code
The azure-pipeline.YAML is a file recognized by Azure to build its pipelines. For this create a pipeline in Azure and configure it to read the azure-pipeline.YAML. That's all we need here! We will do the infrastructure building in the YAML file.
When the pipeline gets executed it reads the YAML file and configures itself. Every time the pipeline runs, it uses the YAML file to build and configure the infrastructure. We can build multiple parallel runs with different configurations from the same code branch. This covers a good practice of building from the same branch.
The below snipped uses a Microsoft Hosted Agent to Build Cucumber Test in 4 threads that run in parallel. The 'options' define the profiles to use to build snapshots. As in the example below, we can now control the number of threads we want to run in this pipeline and can also configure each thread for various configurations such as environment to run, login credentials to use, and test suite choice. You can enable CI on the pipeline in Azure and every time you check in to this branch the pipeline will be configured as per the YAML file and executed. This can be added as a stage to a CD process.
## Maven
## Build your Java project and run tests with Apache Maven.
## Add steps that analyze code, save build artifacts, deploy, and more:
## https://docs.microsoft.com/azure/devops/pipelines/languages/java
#
variables:
- name: BuildParameters.mavenPOMFile
value: pom.xml
name: $(date:yyyyMMdd)$(rev:.r)
resources:
repositories:
- repository: self
type: git
ref: refs/heads/{put branch name here}
jobs:
- job: Batch 1 Regression
displayName: Batch 1 Regression
pool:
vmImage: vs2017-win2016
steps:
- checkout: self
- task: Maven@3
displayName: Maven pom.xml
inputs:
mavenPOMFile: $(BuildParameters.mavenPOMFile)
goals: compile verify
options: -PLoginSet1 -Puat -Dcucumber.options="--tags @demo01"
testResultsFiles: '**/target/cucumber-reports/Cucumber.xml'
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
condition: succeededOrFailed()
inputs:
SourceFolder: $(system.defaultworkingdirectory)
Contents: '**/*.jar'
TargetFolder: $(build.artifactstagingdirectory)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'
condition: succeededOrFailed()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
- job: Job_2
displayName: Test Demo 2
pool:
vmImage: vs2017-win2016
steps:
- checkout: self
- task: Maven@3
displayName: Maven pom.xml
inputs:
mavenPOMFile: $(BuildParameters.mavenPOMFile)
goals: compile verify
options: -Pcs2 -Ptest -Dcucumber.options="--tags @demo02"
testResultsFiles: '**/target/cucumber-reports/Cucumber.xml'
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
inputs:
SourceFolder: $(system.defaultworkingdirectory)
Contents: '**/*.jar'
TargetFolder: $(build.artifactstagingdirectory)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop copy'
condition: succeededOrFailed()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
- job: Batch 2 Regression
displayName: Batch 2 Regression
pool:
vmImage: vs2017-win2016
steps:
- checkout: self
- task: Maven@3
displayName: Maven pom.xml
inputs:
mavenPOMFile: $(BuildParameters.mavenPOMFile)
goals: compile verify
options: -PLoginSet2 -Ptest -Dcucumber.options="--tags @demo03"
testResultsFiles: '**/target/cucumber-reports/Cucumber.xml'
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory) copy'
inputs:
SourceFolder: $(system.defaultworkingdirectory)
Contents: '**/*.jar'
TargetFolder: $(build.artifactstagingdirectory)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop copy copy'
condition: succeededOrFailed()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
- job: Batch 3 Regression
displayName: Batch 3 Regression
pool:
vmImage: vs2017-win2016
steps:
- checkout: self
- task: Maven@3
displayName: Maven pom.xml
inputs:
mavenPOMFile: $(BuildParameters.mavenPOMFile)
goals: compile verify
options: -Pcs4 -Ptest -Dcucumber.options="--tags @demo04"
testResultsFiles: '**/target/cucumber-reports/Cucumber.xml'
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory) copy'
inputs:
SourceFolder: $(system.defaultworkingdirectory)
Contents: '**/*.jar'
TargetFolder: $(build.artifactstagingdirectory)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop copy copy'
condition: succeededOrFailed()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
- job: Batch 4 Regression
displayName: Batch 4 Regression
pool:
vmImage: vs2017-win2016
steps:
- checkout: self
- task: Maven@3
displayName: Maven pom.xml
inputs:
mavenPOMFile: $(BuildParameters.mavenPOMFile)
goals: compile verify
options: -PLoginSet3 -Ptest -Dcucumber.options="--tags @demo05"
testResultsFiles: '**/target/cucumber-reports/Cucumber.xml'
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory) copy'
inputs:
SourceFolder: $(system.defaultworkingdirectory)
Contents: '**/*.jar'
TargetFolder: $(build.artifactstagingdirectory)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop copy copy'
condition: succeededOrFailed()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
...
Hope this article helps some of you out there looking to automate your QA and DevOps needs.
Opinions expressed by DZone contributors are their own.
Comments