Overview:
In this tutorial, I would like to show you how to create use AssertJ Custom Assertions for Selenium tests.
AssertJ:
AssertJ is a simple assertion library for Java using which assert statements can be written in fluent style.
Fluent APIs make your code readable and easily maintainable. We already have seen few articles on designing Page Objects and Business Workflows in fluent style. In this article, Lets see how we could include fluent assert statements for your automated tests using AssertJ library. If you take a look at the examples in this articles, You could easily compare that with your JUnit/TestNG assert statements and understand the benefits of using AssertJ.
Maven:
To include AssertJ in your Java project, include below maven dependency in your pom file. Check the maven repo here for the latest versions.
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.1</version>
<scope>test</scope>
</dependency>
Once you have included in your pom file, do the below static import in your test classes.
import static org.assertj.core.api.Assertions.assertThat;
Examples:
Lets start with few simple examples.
- boolean check
boolean actual = false;
assertThat(actual).isTrue();
//or
assertThat(actual).isEqualTo(true);
- Sting comparison.
@Test
public void stringCompare(){
String expected = "Test Automation Guru";
String actual = "test automation guru";
assertThat(actual).isEqualTo(expected);
}
Running the above code produces below output.
java.lang.AssertionError:
Expecting:
<"test automation guru">
to be equal to:
<"Test Automation Guru">
but was not.
You can also include some meaningful description for your assert statements.
assertThat(actual).as("AssertJ String Comparison Check").isEqualTo(expected);
The above statement will display,
java.lang.AssertionError: [AssertJ String Comparison Check]
Expecting:
<"test automation guru">
to be equal to:
<"Test Automation Guru">
but was not.
- Not null / blank check.
assertThat(actual).isNotNull()
.isNotBlank();
- Chaining various string checks.
assertThat(actual).doesNotStartWith("Test")
.doesNotEndWith("Guru")
.doesNotContain("automation")
.contains("assertj");
- int comparison.
assertThat(10).isBetween(5,15);
assertThat(10).isPositive()
.isGreaterThan(8)
.isLessThan(12);
- Dealing with date assertions are little bit annoying in general. AssertJ handles that very easily.
LocalDate today = LocalDate.now();
LocalDate yesterday = LocalDate.now().minusDays(1);
LocalDate tomorrow = LocalDate.now().plusDays(1);
assertThat(today).isAfter(yesterday).isBefore(tomorrow);
- You can also use date in String format as shown here.
assertThat(today).isAfter("2015-01-01").isBefore("2016-12-31");
- Chaining various date related assertions together.
Date today = new Date();
assertThat(today).hasMonth(3)
.hasDayOfMonth(24)
.hasHourOfDay(10)
.hasMinute(15);
- List compare
List<String> list = new ArrayList<>();
list.add("test");
list.add("automation");
list.add("guru");
assertThat(list).hasSize(3) //passes
.containsAnyOf("automation", "guru") //passes
.doesNotContain("test"); //fails as it contains test
- List – order of elements should be same
//expected
List<String> expected = new ArrayList<>();
expected.add("guru");
expected.add("automation");
expected.add("test");
//actual
List<String> actual = new ArrayList<>();
actual.add("test");
actual.add("automation");
actual.add("guru");
//no change in the order check
assertThat(actual).containsExactly(expected.toArray(new String[expected.size()]));
It produces below output.
java.lang.AssertionError:
Actual and expected have the same elements but not in the same order, at index 0 actual element was:
<"test">
whereas expected element was:
<"guru">
- If the list order does not matter – as long as all the elements are present
//any order check
assertThat(actual).containsAll(expected);
//OR
assertThat(actual).containsExactlyInAnyOrder(expected.toArray(new String[expected.size()]));
- File related checks. First, I create a simple file with below content and save it as /home/vins/expected-file.txt
This is a sample file I am going to use for assertj comparison.
This file has multiple lines.
AssertJ is a cool library.
If you have not realized yet, may be you will now!
- A simple presence check.
File expected = Paths.get("/home/vins/expected-file.txt").toFile();
assertThat(expected).exists()
.isFile()
.hasExtension("txt");
- Comparing 2 file contents
File expected = Paths.get("/home/vins/expected-file.txt").toFile();
File actual = Paths.get("/home/vins/actual-file.txt").toFile();
assertThat(expected).hasSameContentAs(actual);
- Lets assume that you have a CSV file as shown here on left side. You run your automated tests and downloads a new file which is ‘actual’ – but the file content is as shown here on right side. Basically they have same records. However the order has changed slightly. If you want to do an exact match, use the above file compare approach. If the records order do not matter, we will follow the same approach we did for list compare.
List<String > expected = Files.readAllLines(Paths.get("/home/qa/expected-file.csv"));
List<String > actual = Files.readAllLines(Paths.get("/home/qa/actual-file.csv"));
assertThat(actual).containsAll(expected);
- Soft Assertions. You might already know what it means. In case, if you are not aware, The above assertions we had seen so far is hard assertion. When you have more than 1 assert statements, as soon as an assert statement fails, the remaining assert statements do not get executed. This behvaior is same for all AssertJ/JUnit and TestNG libraries. Soft Assertions on the other hand execute all the assert statements and provide the result of all assertions.
String expected = "Test Automation Guru";
String actual = "Test Automation Guru";
SoftAssertions.assertSoftly(s -> {
s.assertThat(actual).doesNotContain("automation");
s.assertThat(actual).doesNotStartWith("Test");
s.assertThat(actual).doesNotEndWith("Guru");
s.assertThat(actual).isEqualTo(expected);
});
It produces below output.
The following 2 assertions failed:
1)
Expecting:
<"Test Automation Guru">
not to start with:
<"Test">
at AssertJTest.lambda$stringCompare$0(AssertJTest.java:31)
2)
Expecting:
<"Test Automation Guru">
not to end with:
<"Guru">
at AssertJTest.lambda$stringCompare$0(AssertJTest.java:32)
AssertJ Custom Assertions:
As you have seen above, AssertJ covers most of the data types for your assertions. It might be more than enough for our Selenium automated tests. For example, if we need to check if a WebElement is displayed.
WebElement element = driver.findElement(By.id("id"));
//isDisplayed check
assertThat(element.isDisplayed()).isTrue();
However, it would be cool to have a separate assertion library for WebElement – to maintain a well readable and reusable code.
To implement your own assertion, create a new class by extending AbstractAssert class. Check this below sample for WebElement assertion.
public class WebElementAssert extends AbstractAssert<WebElementAssert, WebElement> {
public WebElementAssert(WebElement webElement) {
super(webElement, WebElementAssert.class);
}
public static WebElementAssert assertThat(WebElement webElement){
return new WebElementAssert(webElement);
}
public WebElementAssert isDisplayed(){
isNotNull();
//check condition
if(!actual.isDisplayed()){
failWithMessage("Expected element to be displayed. But was not!!");
}
return this;
}
public WebElementAssert isEnabled(){
isNotNull();
//check condition
if(!actual.isEnabled()){
failWithMessage("Expected element to be enabled. But was not!!");
}
return this;
}
public WebElementAssert isButton(){
isNotNull();
//check condition
if(!(actual.getTagName().equalsIgnoreCase("button") || actual.getAttribute("type").equalsIgnoreCase("button"))){
failWithMessage("Expected element to be a button. But was not!!");
}
return this;
}
public WebElementAssert isLink(){
isNotNull();
//check condition
if(!actual.getTagName().equalsIgnoreCase("a")){
failWithMessage("Expected element to be a link. But was not!!");
}
return this;
}
public WebElementAssert hasAttributeValue(String attr, String value){
isNotNull();
//check condition
if(!actual.getAttribute(attr).equals(value)){
failWithMessage("Expected element to have attr <%s> value as <%s>. But was not!!", attr, value);
}
return this;
}
}
Now lets use our assertion library.
//Launching a site and finding a button element
WebDriver driver = DriverManager.getDriver();
driver.get("https://wrappixel.com/demos/admin-templates/admin-pro/main/ui-notification.html");
WebElement element = driver.findElement(By.cssSelector("div.button-box button.btn-info"));
//expecting a button element to be displayed, enabled and to be a link
assertThat(element).isDisplayed()
.isEnabled()
.isLink();
Since the element was not a link, it is expected to fail.
java.lang.AssertionError: Expected element to be a link. But was not!!
If I chnage the assertion, It passes.
assertThat(element).isDisplayed()
.isEnabled()
.isButton()
.hasAttributeValue("class", "tst1 btn btn-info");
AssertJ Custom Soft Assertions:
Lets see how to make the above AssertJ custom assertion to a soft assertion.
- Create another which extends SoftAssertions.
import org.assertj.core.api.SoftAssertions;
import org.openqa.selenium.WebElement;
public class WebElementSoftAssert extends SoftAssertions {
public WebElementAssert assertThat(WebElement actual){
return proxy(WebElementAssert.class, WebElement.class, actual);
}
}
- Have this method in your base test or utility class. (This is execute-around method design pattern)
protected void assertSoftly(Consumer<WebElementSoftAssert> assertConsumer){
WebElementSoftAssert softAssert = new WebElementSoftAssert();
assertConsumer.accept(softAssert);
softAssert.assertAll();
}
- Then write your assertion as usual.
assertSoftly(s -> {
s.assertThat(element)
.isDisplayed()
.isEnabled()
.isButton()
.hasAttributeValue("class", "tst1 btn btn-info");
});
Summary:
AssertJ is one of the coolest libraries we have in Java. we were able to demonstrate AssertJ Custom Assertions in this tutorial. It makes your test automation script well readable and easily maintainable by chaining various assertions.
Read more about
Happy learning 🙂