We just implemented a test case that adds an address to an account:
private Address newAddress = new Address(
100, "Pine Street", "Langley", "1A1 2B2", "BC", "Canada");
@Test
public void canAddNewAddressTest() {
//open home page
HomePage homePage = new HomePage();
homePage.open();
//go to my account page
//this shows the login page first
homePage.goToMyAccountPage();
//log in to the site
//the user is redirected then to my account page
LoginPage loginPage = new LoginPage();
loginPage.loginWith(username, password);
//go to the page where the new address can be added
MyAccountPage myAccountPage = new MyAccountPage();
myAccountPage.goToAddAddressPage();
//add the new address, save the changes
AddAddressPage addAddressPage = new AddAddressPage();
addAddressPage.add(newAddress);
addAddressPage.save();
//on the confirmation page, check that the address is correct
ConfirmChangesPage confirmChangePage = new ConfirmChangesPage();
Address addedAddress = confirmChangePage.getAddress();
Assert.assertEquals(addedAddress, newAddress);
}
The test is very simple.
It uses an Address object to add a new address to the account.
After the changes are saved, it reads the added address info from the confirmation page into another Address object.
Finally, it compares the 2 Address objects.
The Address class is very simple:
public class Address {
private final int streetNumber;
private final String streetName;
private final String city;
private final String postalCode;
private final String state;
private final String country;
public Address(int streetNumber,
String streetName,
String city,
String postalCode,
String state,
String country) {
this.streetNumber = streetNumber;
this.streetName = streetName;
this.city = city;
this.postalCode = postalCode;
this.state = state;
this.country = country;
}
@Override
public String toString() {
return String.format("Address [streetNumber=%s, streetName=%s, city=%s,
postalCode=%s, state=%s, country=%s]",
streetNumber, streetName, city, postalCode, state, country);
}
@Override
public int hashCode() {
return Objects.hash(city, country, postalCode, state,
streetName, streetNumber);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Address))
return false;
Address other = (Address) obj;
return Objects.equals(city, other.city) &&
Objects.equals(country, other.country) &&
Objects.equals(postalCode, other.postalCode) &&
Objects.equals(state, other.state) &&
Objects.equals(streetName, other.streetName) &&
streetNumber == other.streetNumber;
}
public int getStreetNumber() {
return streetNumber;
}
public String getStreetName() {
return streetName;
}
public String getCity() {
return city;
}
public String getPostalCode() {
return postalCode;
}
public String getState() {
return state;
}
public String getCountry() {
return country;
}
}
The class has the typical methods:
toString() - for displaying the data encapsulated in an object
equals() - for comparing Address objects
get method for each field
hashCode()
Notice something different?
Yes, there are no set methods.
Also, all fields are declared as final.
Why do we need these changes?
Because we want each data object to be immutable.
What does this mean? It means that, once the object is created, its state (the values of the fields of the object) cannot be changed any longer.
Having immutable objects provides numerous advantages
Immutable objects cannot be corrupted by external code, making them more robust and predictable.
Immutable classes are simpler to design and implement, as there’s no need to worry about synchronization or concurrent modification.
What are the implications of using immutable objects?
every time you need an object, since you cannot update existing objects, you need to create a new one
every time your code needs to update a field of the class, you should look into another way of implementing the code
you will have more objects; this is good
There are 2 options for changing the state of an object.
from outside of the class
Since set methods allow the state of the object to be changed by any external code, they are not included.
from inside of the class
To prevent the state of the object to be changed by the methods of the class, all fields are declared as final so their values cannot be updated.
Thanks for reading.
NOTE:
This substack includes a full Selenium project that is built from A to Z.
Find it here.