In this series, so far I have shared about three key pillars of object oriented programming and how can we use those while creating a solid test automation framework. Feel free to revisit those if needed from the following links:
The primary goal of this post will be understanding Polymorphism - the 4th pillar of object oriented programming. Before we start here is the list of take aways from this post:
- What is Polymorphism?
- How Polymorphism is different from Inheritance?
- How to implement Polymorphism?
- What are the benefits of Polymorphism?
- How can we use Polymorphism in testing framework?
If you are looking for answers for the above questions, please continue to reading further.
What is Polymorphism?
The simple english meaning of polymorphism is the condition of occurring something in several different forms. Let's start with that understanding and find out how that concept is relevant and applicable in programming world.
Problem Statement:
You need to create a utility class for performing web actions. As of now only requirement you have is to click on any web element. But you may get more functionality to be added in the future.
You are ready with the first draft of the utility as below:
You have tested your code and it works in chrome browser consistently. You are happy with the output of the utility. You have automated 100 + test cases using the utility. Your customer is happy to see the little bot you have created but suggested that they want to see some more business critical user journeys to be automated as soon as possible. You are excited to take this up and started working on the new user journeys. But to your surprise, the click method you have written is not working consistently in all the new new scenarios in the same browser as above. As an alternative, you would like to use Javascript click for few steps and action class APIs in others. You are thinking few options aloud:
- You do not want to modify the existing click method.
- You want to add new functionality in such a way that your class is flexible enough to except this type if changes in future.
- You do not want to touch the working steps since that may have impact on the overall execution and maintenance.
Voila, you have method overloading as rescue. Welcome to the world of polymorphism :-).
What is unique in method overloading?
- Can add methods with same name with different number of argument.
- Can add methods with same name with arguments of different type.
- Can add methods with same same with different order of arguments.
In the above example, instead of adding methods like clickRegular(), clickJavaScript(), clickActionClass() and so and so forth, we can just use same simple name click with different types or number of arguments as per the need.
Advantages of method overloading:
- Improves readability of the program.
- Its easier to remember and use one method name instead of multiple names when methods are doing similar kind of operation with slight variance.
- Constructors can be overloaded too which helps initialising instance variables with different values.
Key point to remember!
Method overloading happens in compile time and this is known as static binding. Compiler can resolve the method call simply by checking the method signature.
Fun fact:
Do you know the most commonly used overloaded method in Java? I am sure you are going to smile seeing this one :-)
So far we got some understanding about method overloading. We are going to learn about method overriding now and figure it out how this is different from method overloading. In object oriented programming, we can have a method in a class that is overridden in one or more subclasses. Problem statement:
Your test automation framework should support creating two browser capabilities - chrome and fireFox.
First Draft design:
You have decided to create separate classes for each browser with the following methods:
- Set the browser
- Get the browser
- Reset the browser
The first draft of the implementation (version1) will look like this:
If we analyse the first version of the above application, it looks to be working one. We are able to set, get and reset supported browsers.
Let's consider a new requirement to reset multiple open instances of the browsers together. For this requirement we may need to create a new class where we will provide a list of all the open instances of the browsers so that we can reset those together. Here goes the implementation :
And the test class will look like this:
Good news we still have a working code, but we are also seeing few problems now:- If a new browser is introduced, we have to change Reset browser feature code.
- If the count of the browser grows very high, we would have issue in holding the references of the browsers.
- Reset feature code is tightly coupled with all the individual browser Class’s code
- Reset feature class can access other method of the browser class’s which is undesirable.
So how can we solve the above problems? We can use inheritance here so that we can get the benefits of polymorphism (method overriding). Our latest implementation with polymorphism will look like below:
Following are the advantages we got with this version of the implementation:- Readability of the code is improved.
- We are able to maintain a layer of abstraction since now the Reset Browser feature has access to only the reset browser functionality of the individual browser classes.
- Adding new functionality will be easier.
We can use method overriding with inheritance, the compiler can't determine at compile time what method to call the base class one or the subclasses one. The compiler needs to check the type of object to know what method should be invoked which happens at run time in this scenario. This is known as dynamic binding.
Other than the above two main types of polymorphism, java supports few more types of polymorphism and we are going to get a glance of those below:
Coercion:
This occurs when an object or the primitive is cast into some other type done by the compiler to prevent type errors.
Example: String result = "result_1" + 1;
Output: result_11
Operator Overloading:
This refers to a polymorphic characteristic of same symbol or operator having different meanings (forms) depending on the context.
For example, the plus symbol (+) can be used for mathematical addition as well as String concatenation.
Example:
String twoStr = "one" + "one";
int twoInt = 1 + 1;
Output:
twoStr = oneone
twoInt = 2
If you are looking for few more use cases on how to use polymorphism in test automation framework, here are few scenarios:
- Utility classes (refer the example discussed in this post)
- Test driver creation classes
- Business layer - when we need to test polymorphic use cases. For example different user profiles based on role assigned.
Congratulations, you have completed reading about polymorphism with examples. Thank you for being with me till the end of this post.
What you can explore next?
- How to use polymorphism to refactor nested if else conditions?
- Strategy design pattern which relies on polymorphism