How does dependency injection work in Cucumber? - java

I have been trying to inject webdriver into the steps. I have used this instructions and it works well.
The idea is to inject WebDriver into steps classes as a service. At the initial step, you need to add the following dependency.
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-spring</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
There are three main classes which are involved in the dependency injection. Here we introduce them one by one.
BaseUtil
BaseUtil is the class which has an attribute for WebDriverof Selenium. The class is quite simple:
public class BaseUtil {
private WebDriver driver;
public WebDriver getDriver() {return driver;}
public void setDriver(WebDriver driver) { this.driver = driver;}
}
Hook
The Hook class contains #Before, #After. The method testInitialier() is responsible to load the the webDriver file and create an instance, while the method testTearDown() is responsible for closing the browser.
public class Hook extends BaseUtil{
BaseUtil base;
#Before
public void testInitializer(){
File file = new
File(IgniteTaskApplication.class.getClassLoader().getResource("driver/chromedriver.exe").getFile());
String driverPath=file.getAbsolutePath();
System.out.println("Webdriver is in path: "+driverPath);
System.setProperty("webdriver.chrome.driver",driverPath);
base.setDriver(new ChromeDriver());
}
public Hook(BaseUtil base) {
this.base = base;
}
#After
public void tearDownTest(){
base.getDriver().close();
}
}
Steps
And the steps class contains the steps which came from compiled features file. To compile the feature file in Eclipse you need to have Eclipse-Cucumber plugin installed in your Eclipse.
public class ClickButton_Steps extends BaseUtil{
BaseUtil base;
public ClickButton_Steps(BaseUtil base){
super();
this.base=base;
}
#When("^I clcik on the button$")
public void i_clcik_on_the_button() throws Throwable {
cb=new ClickButtonPage(base.getDriver());
cb.navigator();
}
// The other steps ...
}
How do i run it?
Open the feature file -> Run as -> Run with Junit
Question
I am wondering what is the order of running methods in a way which it leads to dependency injection?
I guess the order is as following:
Junit calls #Before method which is testInitializer()
The testInitializer()is in Hook class so it needs to make an instance of Hook class.
It leads to call the constuctor of the Hook class.
But, i cannot understand the rest of the steps. Maybe even it does not true at all. I mean, I have a functional code but i cannot explain how it works?

As I understand you correctly you use JUnit as a test framework with cucumber-spring. JUnit provides the following lifecycle.
When you annotate the method with annotation #Before that it will call this method before each test that you have.
As for #After could be used for cleaning resources and call after each test.
Your test flow when you run the test:
testInitializer
i_clcik_on_the_button
tearDownTest
In addition, you could use logging (slf4j) instead of System.out.println and it will be easier to track test flow.

Related

How to use correctly TestNG annotations with Cucumber framework

I am building TestNG and Cucumber framework, and want to use TestNG annotations like #BeforeMethod, #AfterMethod which will run setUp and tearDown methods before and after each scenario. It works fine if I keep all my Cucumber scenarios in separate feature files. But if I have multiple scenarios in the same feature file #AfterMethod is not running after each scenario.
Also have issues if using cucumber Before and After, they work fine only if I put them in StepDefinition file below:
public class StepDefinition extends Base {
#Before
public void setUp() throws Exception {
openBrowser();
maximizeWindow();
// implicitWait(30);
deleteAllCookies();
// setEnv();
}
#After
public void quit() throws IOException, InterruptedException {
driver.quit();
}
#Given("^Navigate to ACT landing page$")
public void navigate_to_ACT_landing_page() throws Throwable {
LandingPage landingPage = new LandingPage();
landingPage.navigateToLandingPage();
}
#Then("^Verify landing page is rendered$")
public void verify_landing_page_is_rendered() throws Throwable {
LandingPage landingPage = new LandingPage();
landingPage.landingPageRendered();
}
}
But if I put them in separate class (like below) they don't work (in documentation says that they can be put anywhere in the project)
package com.act.hooks;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import java.io.IOException;
import com.moodys.act.base.Base;
public class Hooks extends Base {
#Before
public void setUp() throws Exception {
openBrowser();
maximizeWindow();
// implicitWait(30);
deleteAllCookies();
// setEnv();
}
#After
public void quit() throws IOException, InterruptedException {
driver.quit();
}
}
There are cucumber provided tags/hooks #Before and #After which runs just before and after each scenario where you can have your setup and teardown code included. Is there any specific reason you want to use testng annotations for doing so ?
This link may help for cucumber #Before and # After tags.
https://www.google.com/amp/www.automationtestinghub.com/cucumber-hooks-before-after/amp/
Cucumber does not recommend to prepare and clean states using TestNG annotations.
In order to take maximum benefits of TestNG, you can try using pure TestNG implementation for BDD with QAF. It considers each scenario as TestNGMethod.
If you want to use cucumber then you can add qaf-cucumber dependency and use TestNG factory. It will allow to use TestNG listeners and lifecycle methods (#BeforeMethod, #AfterMethod). When using cucumber with qaf you can choose either to utilize TestNG life-cycle or cucumber life-cycle.
Furthermore, if you are working with webdriver or appium it has inbuilt thread-safe driver management so you don't need to worry about driver management.

How to add test method's comment sections from IntelliJ automatically?

I am creating test classes from the IntelliJ automatically like following
This gives me the test class as following in the related module accordingly:
public class MyClassTest {
#Test
public void myMethod() {
}
}
What I am looking for is that
Does IntelliJ can automatically insert Given When Then comment sections into test methods?
I am searching for something like following:
public class MyClassTest {
#Test
public void myMethod() {
// Given
// When
// Then
}
}
These sections are useful for the reader coming after some times passed but usually missed while writing test methods. I am looking for a solution to add this behavior to IDE.
Of course. Navigate to Settings - Editor - File and Code templates - JUnit Test Method

TestNG nested tests or test steps

I'm wondering is it possible to make TestNG show in it's report something like nested tests or test steps.
The thing is that I have pretty big integration test cases and it would be nice if I could decouple it on some steps, say, with something like allure's #Step annotation.
For now the test case is shown as one huge separate entry in intellij IDEA report with a lot of logs which is very difficult to go through and analyze.
You can use createNode method of ExtentTest class. it will creating node under main test.
I've never tried to use Inner TestNG classes but that might be possible and I do believe IntelliJ would render the nested view. You could make a simple little project to try it out. There is a guy who seems to have tried inner classes here: http://makeseleniumeasy.com/2018/05/13/testng-tutorials-12-how-to-run-inner-testng-class-from-testng-xml/ . Let me know if it works. Won't know if IntelliJ renders the nesting until you try.
Bonus: If that works, would be interesting to execute your TestNG using Gradle testng plugin and see if HTML report also renders the nesting.
Inner classes can be used to form groups. For one level of nesting the inner classes must be made public.
Try the following:
public class foo {
public class bar1 {
#Test
public void test11() {System.out.println("test11");}
#Test
public void test12() {System.out.println("test12");}
}
public class bar2 {
#Test
public void test21() {System.out.println("test21");}
#Test
public void test22() {System.out.println("test22");}
}
}
JUnit does have #Nested to group them and you can use the shortcut cmd+R etc. to run them, especially if you have lots of test cases
For TestNG, either split them into different (inner) classes, or use structure view in IntelliJ (https://www.jetbrains.com/help/idea/viewing-structure-of-a-source-file.html)
Right-click all those tests that you want to run
Now you can use groups feature of TestNG E.g.:
class RecordsAccessorTest {
#BeforeMethod(groups = "NewRecordGroup")
public void setUp() {
// some set up for only new record creation is tested
}
#Test(groups = "NewRecordGroup")
public void testNewRecordCreation_happyPath() {...}
#Test(groups = "NewRecordGroup")
public void testNewRecordCreation_errorPath() {...}
#Test
public void someOtherTestNotInGroup() {...}
}

How can I use google guice DI outside of testNG test classes in a testNG based framework?

it is very simple to implement injection of objects into a testNG test class, it is handled mostly for us, however how can I build google guice DI into my framework and use it for classes which are not necessarily tests?
I want to inject using simple dependency injection for dependencies of my Page Object classes, these are nothing really to do with testNG, so how can we get the dependencies initialized for those?
Here is a simple example piece of code I want to replace:
public class HeaderComponent extends AbstractBasePageObject {
private static final Logger LOG = LoggerFactory.getLogger(HeaderComponent.class);
private MenuComponent menu = new MenuComponent(getDriver());
public HeaderComponent(NgWebDriver ngdriver) {
super(ngdriver);
}
public MenuComponent getMenuComponent() {
return menu;
}
}
This class is absolutely nothing to do with testNG itself, so how can I initialize everything for the outcome of:
#Inject
MenuComponent menu
Everything I try the menu throws a nullPointerException because I am having trouble having guice somewhat loaded I think.
I have create some general example for you - test with injection example
It works as you're expecting, I hope. It provides some test configs, injects them to driver and at last driver is injected in test component.
Result test looks like:
import com.google.inject.Inject;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
#Guice(modules = {TestModule.class})
public class SimpleTest {
#Inject
ComponentUnderTest component;
#Test
public void sampleTest() {
System.out.println(component.getParamToTest());
System.out.println(component.param);
System.out.println(component.elseone);
}
}

#BeforeClass runs multiple times for the same class in eclipse

I am writing some junit tests in eclipse and I need to do some time consuming setup before the tests. Appeared that #BeforeClass should be the way to do this. I currently tested this on a class that has 2 #Test functions.
When I right click on a class in eclipse and chose "Run As" -> "JUnit Test" I can see that the #BeforeClass is executed before both functions.
I even tried to change #BeforeClass to #Before and stored in a boolean whether we had already executed this function, but it seems that eclipse created two class objects from the same class, one for each test to run so that did not help either.
So what should I do to have a setup function run only one time even if I have many tests ? Or am I just using eclipse incorrectly when trying to run the tests ?
The setup is something like this:
public class SuperClass {
#BeforeClass
public void { // do timeconsuming setup }
}
public class TestClass extends SuperClass {
#Test
public void test1() { // perform first test }
#Test
public void test2() { // perform second test }
}
Making static the method annotated with BeforeClass may be the solution:
#BeforeClass
public static void
#BeforeClass methods should be static in order to be executed only once.

Categories

Resources