Locking the test data when tests are running in parallel
Need for Data Locking
When tests run in parallel - it may so happen that they access the same test data. This could cause unexpected behavior in tests and lead to failures.
For instance, two tests signing in with the same credentials - while one test added an item to the cart, another test could empty the cart - so the first test is going to fail for sure as it did not find the item added in the cart.
Ekam provides a mechanism to lock the test data once it has been supplied to the test. Once the test execution is complete the lock on test data would be released, so that another test could consume the test data.
Let us add 2 more secondary addresses to uat/address.json
{
"default_address": [
{
"firstName": "Puja",
"city": "Delhi",
"pinCode": "22002"
}
],
"secondary_address": [
{
"firstName": "Puja",
"city": "Chennai",
"pinCode": "44004"
},
{
"firstName": "Puja",
"city": "Hyderabad",
"pinCode": "55005"
},
{
"firstName": "Puja",
"city": "Bangalore",
"pinCode": "66006"
}
]
}
Now we have 3 secondary addresses - cities being Chennai, Hyderabad & Bangalore.
Add tests
Let us add 3 tests that fetch secondary addresses
package ekam.example.web;
import com.google.inject.Inject;
import com.testvagrant.ekam.testBases.testng.WebTest;
import dataclients.address.Address;
import dataclients.address.AddressDataClient;
import org.testng.annotations.Test;
public class DataSetsClientTest extends WebTest {
@Inject private AddressDataClient addressDataClient;
@Test(groups = "web")
public void shouldGetSecondaryAddress() {
Address secondaryAddress = addressDataClient.getSecondaryAddress();
System.out.println(secondaryAddress.getCity());
}
@Test(groups = "web")
public void shouldGetSecondaryAddressAgain() {
Address secondaryAddress = addressDataClient.getSecondaryAddress();
System.out.println(secondaryAddress.getCity());
}
@Test(groups = "web")
public void shouldGetSecondaryAddressOnceAgain() {
Address secondaryAddress = addressDataClient.getSecondaryAddress();
System.out.println(secondaryAddress.getCity());
}
}
Let us make sure all 3 tests are running in parallel :
task runWebTests(type: Test) {
filter {
excludeTestsMatching "*.mobile.*"
excludeTestsMatching "*.api.*"
excludeTestsMatching "*.db.*"
}
outputs.upToDateWhen { false }
useTestNG {
parallel = "methods"
threadCount Integer.parseInt(System.getProperty("sessions", "3"))
includeGroups System.getProperty("tags", "web")
testLogging.showStandardStreams = true
useDefaultListeners true
outputDirectory = file("$buildDir/" + System.getProperty('tags', 'NONE'))
}
}
Execute tests with NO locking in place
Let us execute tests
./gradlew clean runWebTests -Dconfig=uat
The output is :
Bangalore
Bangalore
Bangalore
This shows all 3 tests picked the first test data object from the JSON. All tests are picking the same test data.
Execute tests with locking in place
Let us introduce locking and see the behavior now :
How do we add lock once the test data is retrieved from JSON?
Pass third parameter to getValue() as true
package dataclients.address;
import com.testvagrant.ekam.commons.data.DataSetsClient;
public class AddressDataClient extends DataSetsClient {
public Address getDefaultAddress() {
return getAddress(DataKeys.DEFAULT_ADDRESS);
}
public Address getSecondaryAddress() {
return getAddress(DataKeys.SECONDARY_ADDRESS);
}
private Address getAddress(String key) {
return getValue(key, Address.class, true);
}
private static class DataKeys {
public static final String DEFAULT_ADDRESS = "default_address";
public static final String SECONDARY_ADDRESS = "secondary_address";
}
}
Once the address is served to the test under execution, a lock is acquired until the test is complete. The lock would be released once the test’s execution is complete.
Now let’s execute the tests with lock.
./gradlew clean runWebTests -Dconfig=uat
The output is :
Chennai
Hyderabad
Bangalore
This shows all 3 tests picked three different test data object from the JSON.