JUnit is a Java-based, open-source framework to help you execute unit testing. JUnit is used primarily to test each and every unit or component of your application like classes and methods. It helps to write and run repeatable automated tests, to ensure your code runs as intended. The framework offers support to Selenium test automation for web-apps or websites.
This article is my attempt to help you use JUnit annotations in Selenium as a professional tester would. We would be looking at examples of JUnit annotations in Selenium, their order of execution, along with some special JUnit annotations that are used for a specific purpose. We will also be looking into a collective code for executing each example of JUnit annotation in Selenium. At last, we will perform cross browser testing with Selenium Grid using JUnit annotations.
Before we head on to JUnit annotations in Selenium, let us quickly recap the reasons behind JUnit’s popularity among the tester community.
JUnit without a doubt, is considered as one of the top Java test frameworks. Below are the pointers behind it.
As stated in the pros above, JUnit Annotations in Selenium help to identify the type of methods we have defined in our test code. But the question that arises here is, how do we use JUnit annotations in Selenium? What are the keywords that defines JUnit annotations in Selenium? When to use JUnit annotations in Selenium? If you are going through the same questions then I will help you get to the answer of them by the end of this article.
So, basically Annotations are the meta-tags that provides additional information about the methods and classes defined in our code structure.
In order to execute Selenium WebDriver testing with JUnit, it is necessary to add JUnit Annotations in our script.
Note: JUnit Annotations would only be accessible in JUnit 4 plus versions and it requires at least JDK(Java Development Kit) 1.5 version.
Below is the list of every JUnit annotation in Selenium that will be covered in this blog.
Now, we look at each annotation one by one and at the end, I’ll present you the entire compiled code representing all the annotations along with the console output, at the end of this section.
@BeforeClass
@BeforeClass
public static void SetUpClass()
{
//Initialization code goes here
System.out.println("This is @BeforeClass annotation");
}
@Before
This annotation is used whenever we want to initialize any object for the time the method is being used. Suppose, we are having 5 test cases, the Before method will be called before each test method for 5 times. So, it would be invoked every time the test case is executed. This annotation is usually used for setting up the test environment.
@Before
public void SetUp()
{
// Setting up the test environment
System.out.println("This is @Before annotation");
}
@Test
This annotation tells JUnit that the public void method() to which it is attached can be run as a test case. This annotation includes the test method for an application that you want to test. A single automation test script may comprise numerous test methods in it.
@Test
public void Addition()
{
c= a+b;
assertEquals(15,c);
System.out.println("This is first @Test annotation method= " +c);
}
@Test
public void Multiplication()
{
c=a*b;
assertEquals(50,c);
System.out.println("This is second @Test annotation method= " +c);
}
@After
Whatever we have initialized in @Before annotation method, that initialization should be released in @After annotation method. So, this annotation is executed every time after each test method. The primary purpose of @After annotation is to teardown. Teardown is a process of deleting temporary data. Teardown can also be used to define the default values or to wipe the slate clean of the test environment.
@After
public void TearDown()
{
// Cleaning up the test environment
c= null;
System.out.println("This is @After annotation");
}
@AfterClass
Whatever we have initialized in @BeforeClass annotation method, that initialization should be released in @AfterClass annotation method. So, this annotation is executed once but it will be executed after all tests has finished executing.
@AfterClass
public static void TearDownClass()
{
//Release your resources here
System.out.println("This is @AfterClass annotation");
}
@Ignore
This annotation tells JUnit that this method shall not be executed. In scenarios, where our code module is not ready in a particular test case, we can temporarily put that code module in @Ignore annotation method to avoid test case failure. Native JUnit 4 offers powerful reporting to help you realize the count of tests that were ignored along with count of tests that run and count of tests that failed.
@Ignore
public void IgnoreMessage()
{
String info = "JUnit Annotation Blog" ;
assertEquals(info,"JUnit Annotation Blog");
System.out.println("This is @Ignore annotation");
}
Here is the compiled code with output representing all the JUnits annotations in Selenium WebDriver:
package JUnitAnnotationBlog;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
public class JUnitAnnotations {
int a=10;
int b=5;
Object c;
@BeforeClass
public static void SetUpClass()
{
//Initialization code goes here
System.out.println("This is @BeforeClass annotation");
}
@Before
public void SetUp()
{
// Setting up the test environment
System.out.println("This is @Before annotation");
}
@Test
public void Addition()
{
c= a+b;
assertEquals(15,c);
System.out.println("This is first @Test annotation method= " +c);
}
@Test
public void Multiplication()
{
c=a*b;
assertEquals(50,c);
System.out.println("This is second @Test annotation method= " +c);
}
@After
public void TearDown()
{
// Cleaning up the test environment
c= null;
System.out.println("This is @After annotation");
}
@AfterClass
public static void TearDownClass()
{
//Release your resources here
System.out.println("This is @AfterClass annotation");
}
@Ignore
public void IgnoreMessage()
{
String info = "JUnit Annotation Blog" ;
assertEquals(info,"JUnit Annotation Blog");
System.out.println("This is @Ignore annotation");
}
}
Console Output Of JUnit Annotations in Selenium WebDriver
A basic process flowchart of JUnit Annotations that would help you understanding the flow, step by step.
In earlier section we covered most basic JUnit annotations in Selenium. Now, I will show you some advanced JUnit annotations along with their specific purpose.
@ParameterizedTest
This annotation is somewhat similar to @Test annotation, the difference is that it is used to identify the parameterized test methods. We can also make use of @ValueSource annotation for providing the method parameters after annotating the test method. Keep in mind, that the data type for a parameters could be of any type such as String or Integer.
In the below sample code, the variable “data” of String type passed as a parameter takes an argument from the source annotation.
The primary purpose of this annotation is to run a test multiple times with different arguments.
Note: Add the below libraries before using these annotation
org.junit.jupiter.params.ParameterizedTest
org.junit.jupiter.params.provider.ValueSource
Example:
@ParameterizedTest
@ValueSource(strings = {"LambdaTest", "JUnit", "Annotations", "Blog"})
void ExampleCode(String data)
{
assertNotNull(data);
}
Output:
@RepeatedTest
This annotation which has been introduced in JUnit 5 is used to run test method several times as per the requirement. The number of repetitions that you want a test to go under, can be passed as a parameter to @RepeatedTest annotation.
Example
@Test
@RepeatedTest(5)
public void Addition()
{
int a=10;
int b=5;
Object c;
c= a+b;
assertEquals(15,c);
System.out.println("This is @RepeatedTest annotation method= " +c);
}
Output
@RunWith
When a class is annotated with @RunWith annotation, JUnit invokes the class which are annotated to execute the test. This annotation basically runs with @SuiteClasses Annotation which specifies a group of many classes to be executed. Each class in a suite executes after the execution of prior running class.
Note: It is necesarry to add org.junit.runner.RunWith librarby in order to use this annotation.
Example
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestSample1.class,
TestSample2.class,
TestSample3.class,
TestSample4.class,
TestSample5.class,
})
public class JunitTest {
// This class remains empty, it is used only as a holder for the above annotations.
}
@Parameters
Note: Do not get confused between @ParameterizedTest annotation and @Parameters annotation. @Parameters annotation requires @RunWith annotation to specify that the test would run with Parameterized runner. However, in @ParameterizedTest annotations, @ValueSource would be used as a source annotation to pass arguments.
While using @Parameters annotation, we use @RunWith annotation to specify that the test will run with Parameterized Runner. The runner looks for a method that initialize the test, provides values for the test and executes the test.
In the below code, the value-set is defined as list Object arrays which is annotated with @Parameters. A parameterized test is a common test which is executed again and again using test parameters.This saves a lot of time for developers in executing the same test with different input types.
Example
@RunWith(Parameterized.class)
public class Blog1 {
String name, password;
@Parameters
public Object[][] getData()
{
Object[][] info = {{"ramit1","ramitd11"}, {"ramit2","ramitd22"}};
return info;
}
public Blog1(String id, String pass)
{
this.name = id;
this.password= pass;
}
@Test
public void Sample()
{
SampleCode.login(name, password);
}
}
Below is the code for SampleCode class used in above example:
public class SampleCode
{
public static void login(String name, String password)
{
System.out.println(“Login credentials are ” + name + password ) ;
}
}
Output
These test annotations in JUnit have multiple attributes that can be used for our test method:
1) timeout – To specify timeout for each test case, timeout attribute is specified within @Test annotation. Timeout time is specified in milliseconds. For example, suppose, you know your particular test case takes around 15-20 seconds to get executed and you want your test to fail if it takes more than 20 seconds to get executed, then you can use this attribute as @Test(timeout=20000) for your particular test case. If an execution fails then the progress bar would get red instead of green.
Example:
@Test(timeout=10000)
public void ExampleCode() throws InterruptedException
{
System.setProperty("webdriver.chrome.driver","C:\\Users\\Lenovo-I7\\Desktop\\Selenium\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.lambdatest.com");
driver.manage().window().maximize();
driver.findElement(By.xpath("//*[@id=\'bs-example-navbar-collapse-1\']/ul/li[6]/a")).click();
Thread.sleep(2000); //Login Page Button
driver.findElement(By.xpath("//*[@id='app']/section/form/div/div/input[1]")).sendKeys("[email protected]");
//Username
driver.findElement(By.xpath("//*[@id=\'app\']/section/form/div/div/input[2]")).sendKeys("Hello1234");
Thread.sleep(2000); //Password
driver.quit();
}
Now, if you want to put this same timeout for multiple test cases, it is not necessary to add timeout attribute within each and every @Test annotation you have specified in your script. In such case, you can use @Rule annotation to define a global timeout that would be applicable for each @Test method annotation of your script.
Example:
@Rule
public Timeout globalTimeout = Timeout.seconds(10); // 10 seconds max per test method
2) expected – This is a special feature introduced by JUnit 4 which provides the facility to trace an exception that was expected from the execution of a particular code. There are different kinds of exceptions that are probably expected while running a code, such as, NoSuchMethodException, ArithmeticException, IndexOutOfBoundsExceptions etc. For example, you expect occurrence of exception from your code when a particular number is divided by zero, in this case, you would be using ArithmeticException. If the excepted exception does not occur then the test execution will fail.
Example:
@Test(expected= ArithmeticException.class)
public void ExampleCode()
{
int a= 10,b=0,c;
c=a/b;
System.out.println("Value= " +c);
}
Cross Browser Testing, as the name suggests, is a practice to test your website or web-application on different browsers, browser versions and on different operating systems as well, making sure that the particular application works as expected in desired configurations without any compromise in quality. Primarily, with browser compatibility testing, we test the appearance and functionality of a website.
The purpose of cross browser testing is to provide consistent behavior of any application on different browsers, devices and platforms. Selenium helps us to perform automated cross browser testing for pacing our go-to-market delivery.
Selenium comes under 4 variants -
Selenium Grid would be the best option for automated cross browser testing, as it empowers users to perform parallel testing in Selenium for which we would be using Java with JUnit framework. For this, we would be running our automated test script on LambdaTest, a cross browser testing tool to realize the use of common JUnit annotations in Selenium by performing cross browser testing
Below is the code using which will first go to Apple’s website → iPad → iPad Air → Why iPad. Our code will then capture a screenshot of the last webpage i.e. Why iPad, and will store it in my local machine. I will be making use of LambdaTest Selenium Grid for running my below automation script to perform automated cross browser testing.
package LambdaAutoPack;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
public class JUnitAnnotation {
public String username = "ramitdlambdatest";
public String accesskey = "abcd1234";
public static RemoteWebDriver driver = null;
public String gridURL = "@hub.lambdatest.com/wd/hub";
boolean status = false;
@BeforeClass
public static void setUpClass()
{
System.out.println("Cross Browser Testing on LambdaTest");
System.out.println("Testing on High Sierra, Chrome 72, Resolution-1920x1080");
}
@Before
public void setUp() throws Exception {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("browserName", "Chrome");
capabilities.setCapability("version", "72.0");
capabilities.setCapability("platform", "macOS High Sierra"); // If this cap isn't specified, it will just get the any available one
capabilities.setCapability("build", "JUnit Annotations");
capabilities.setCapability("name", "MyBlog");
capabilities.setCapability("network", true); // To enable network logs
capabilities.setCapability("visual", true); // To enable step by step screenshot
capabilities.setCapability("video", true); // To enable video recording
capabilities.setCapability("console", true); // To capture console logs
capabilities.setCapability("resolution","1920x1080");
try {
driver = new RemoteWebDriver(new URL("https://" + username + ":" + accesskey + gridURL), capabilities);
} catch (MalformedURLException e) {
System.out.println("Invalid grid URL");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@Test
public void testSimple() throws Exception {
try {
driver.get("https://www.apple.com/");
driver.manage().window().maximize();
driver.findElement(By.xpath("//*[@id=\'ac-globalnav\']/div/ul[2]/li[3]")).click();
Thread.sleep(2000);
driver.findElement(By.cssSelector("#chapternav > div > ul > li.chapternav-item.chapternav-item-ipad-air > a")).click();
Thread.sleep(2000);
driver.findElement(By.linkText("Why iPad")).click();
Thread.sleep(2000);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@After
public void tearDown() throws Exception {
if (driver != null) {
((JavascriptExecutor) driver).executeScript("lambda-status=" + status);
}
}
@AfterClass
public static void teardownClass() throws IOException
{
File screenshotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshotFile, new File("D:\\Testing.png"));
driver.quit();
}
@Ignore
public void IgnoreMethod()
{
System.out.println("Some modules are not yet ready, please ignore");
}
}
The above code will trigger my test in Google Chrome 72 on Mac High Sierra. If you wish to perform the test on some other browser + OS configuration then you can do so by simple changing the desired capabilities. LambdaTest provides a DesiredCapabilities Generator to help you with coded values based on your selections from drop-down list values.
Since the @BeforeClass annotation method executes only once, I have mentioned the conclusion of this script there itself i.e. Cross Browser Testing on operating system-High Sierra, browser- Chrome, version-72 and resolution- 1920×1080
Coming to @Before annotation method, I have passed the desired capabilities from the capability generator provided by LambdaTest which defines the configurations(OS, Browser, Browser version, Resolution) on which you want your test to run on along with the desired Build name. The same capabilities would be used for each test method since the @Before annotation method executes before each test case.
The @Test annotation method would include your test case of an application that you want to test. In this test method I have written a small automation script that would execute on LambdaTest Selenium Grid which includes live video streaming of selenium test and show the output on IDE console as well. You can create as many @Test annotation depending upon your different project test case executions.
The @After annotation method that executes after each test method shows the status of each test case that whether it has passed or failed. According to the status, you can decide whether the test case needs any improvisation or not.
The @AfterClass annotation method which gets executed only once after the execution of all the test methods, would take the screenshot of the web page that was last accessible through the script and would save the screenshot in the mentioned directory/folder.
@Ignore annotation would just show that some modules of this particular web application has not been fully developed and are still in progress. So, the @Ignore annotation method won’t show any output.
Output
Below is the video that would show you the complete execution of my above automation test script on LambdaTest Selenium Grid.
We have covered all the JUnit annotations in Selenium along with their explanation and sample code. We have also performed automated cross browser testing with the help of JUnit annotations in Selenium Grid on a cloud-based cross browser testing tool, LambdaTest.
JUnit annotations are very powerful feature of JUnit, and help to improve code structure by making JUnit tests easier and more readable. Use of these annotations totally depends on your project requirement, using an appropriate annotation at correct place would be very helpful for developers as well as for other team members.
Remember, JUnit annotations for Selenium would only work in JUnit 4 plus versions and would also require to import this particular library, “org.junit.”
Execute your automation script using JUnit annotations on LambdaTest Selenium Grid now! Happy testing. 🙂
Previously published at https://www.lambdatest.com/blog/tutorial-on-junit-annotations-in-selenium-with-examples/