Dependency
In software development it is a situation where one class or module relies on another, to function correctly.
I have Class A and Class B now the object of Class B should be in Class B, if i create the object of B in Class A , whenever i make changes in Class B then i should make changes in Class A as well. This is called dependent, Class B is dependent on Class A.
Dependency Injection:
A framework or design pattern that allows a class to receive its dependencies from an external source rather than creating them. This promotes loose coupling and easier testing by injecting the required dependencies at runtime. When the code is written in small level or for small project it doesn't matter but when you come to more number of codes for bigger project to make software, it will be useful, while adding new features as well. When Class B is dependent on A likewise if more number of classes are dependent the changes has to be make in all such classes to avoid this Dependency injection comes into picture.
Why do we need Dependency Injection in Cucumber?
Single responsibility principle: States that a class should have only one reason to change ,i.e., it should have only one job or responsibility.
Loosely coupled: components are less dependent on each other if in future making changes in one component less likely to impact others.
Share the state between multiple-step definition files: without a centralized mechanism it is quite difficult, in that case Picocontainer allows to share objects and their state across different step definition, by injecting the same instance of dependency where needed.
(Cucumber does not support shared features)
Reusable code: You can create reusable components that are tightly bound to a specific implementation
Ease to testing.
Pico container
It is a lightweight Dependency Injection container for Java especially for cucumber. It is used to manage object lifecycles and dependencies, allowing for better separation of concerns and more maintainable code. It is well suitable for simple requirements, a full feature compared to other containers like Spring or Google Guice.
How Dependency Injection works?
How to implement DI into cucumber framework with Pico container?
Pico container : It is a lightweight Dependency Injection container for java. It is used to manage object lifecycle and dependencies, which allows to create more maintainable code, Pico container particularly suits simple Dependency Injection needs like cucumber framework when compare to other dependencies like Google Guice and Spring which are overheaded.
Constructor Level Injection: Your step definition classes receive dependencies (like WebDriver) via their constructors.
here the dependencies are passed through constructor, promotes better testability ,required dependencies at object level.
Field Level Injection: You could also inject dependencies directly into fields,(using annotations @Inject). but constructor injection is more common and preferred for better testability and clarity.
here the dependencies are injected field level , drawback is it will lead to issues with testability and lifecycle management
Implementation steps:
Step1:pom.xml (Include dependencies for Cucumber and PicoContainer.)
Adding the necessary dependencies in the project Pom.Xml file to include the one below
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>7.18.1</version>
</dependency>
Step 2:Create PicoContainer Configuration Class:
Create a custom factory class to configure Pico container
public class TestContext {
private WebDriver driver;
private DriverFactory driverFactory;
private WebDriverWait wait;
// initializing the DriverFactory
public TestContext() {
this.driverFactory = new DriverFactory();
this.driver = driverFactory.initialiseBrowser("chrome");
this.wait = new WebDriverWait(driver, Duration.ofSeconds(30));
}
// WebDriver instance
public WebDriver getDriver() {
return driver;
}
// driver close
public void closeDriver() {
driverFactory.closeDriver();
}
public WebDriverWait getWait() {
return wait;
}
}
Step3: Step Definitions Support Injection setting : Modify step definition class to use constructor injection for dependencies like WebDriver
public LoginSteps(TestContext context) {
this.driver = context.getDriver();
this.loginPage = new LoginPage(driver);
this. wait = new WebDriverWait(driver, Duration.ofSeconds(30));
}
Step 4:by default constructor creation and inject for page objects
Configure Cucumber to use the custom Pico container factory, also the page object should be designed to receive the dependencies through the constructor for maintainability.
There are two step definition files which are referring a static page object , the object static is continuing for Scenario 2 also , this needs to be avoided why because if the the state is shared with scenario we can lead to data leaks .
What happens after adding Pico container , here it serves the object which is required for a step-definition file ,new object will be created by Pico container dependency injector and the state will be shared within the steps.
The lifecycle of the injected Object WebDriver here typically tied with scenario, the step-definition files within the single scenario share same instance of an injected object. When there is multiple step-definitions with the same scenario will share the same web driver instance , there will not be any sharing of state between the scenarios, each scenario will be getting new instance.
Lets consider Login page and My info page and follow the explanation:
Static WebDriver:
Since the WebDriver is static it becomes shared state ,hence same instance will be shared across the test
When test run parallel, it attempts to perform the action in same browser instance concurrently. It also end up with the issues like one test navigates away from the page that is on test is performing the action in one browser another browser it opens but dint perform any action . Also cross contamination also occur like Data leaking the username and password from the My info page password into while performing the login page action and test failed Finally the test got failed .But when i perform the same with the single separate Test it worked fine and test case was pass.
WebDriver Injected:
After injecting dependency injection of WebDriver instance through Pico container
Isolated instance: Each test get its own instance through injection, here the action performed in one Test will not affect the other. Login page perform its action separately in one browser instance and Myinfopage in separate instance. So its thread safety while running in parallel mode each test with the help of individual driver instance. By avoiding shared state the was all pass. So we can keep adding features as the test suite grows and want to add more tests can add with confident there will not be any interfere with each as they become independent now.
As like the WebDriver instance we can also perform same incase of login credentials page which will be required for all other page or feature .
For better understanding checkout the video of execution i have attached. Below is the link
Conclusion:
Pico container makes code more reliable through decoupling ,promotes the modularity by making the different parts of the application into independent. When we involve in big application coding since everything is interconnected ,while adding new feature we can test separately and link to the existing application features without conflict. performance would faster as its lightweight dependencies, and manually addition falls under the drawback.
Happy Coding!
Comments