Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit 911edd1

Browse files
committed
added documentation for TestNG support module
1 parent 7585480 commit 911edd1

File tree

3 files changed

+259
-4
lines changed

3 files changed

+259
-4
lines changed

documentation/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- [Internet Explorer](chapters/support-ie.md)
2727
- Testing
2828
- [JUnit](chapters/support-junit.md)
29+
- [TestNG](chapters/support-testng.md)
2930
- Integration
3031
- [Spring 4](chapters/support-spring4.md)
3132
- Advanced Topics
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
[Home](../README.md)
2+
3+
# WebTester's TestNG Listener
4+
The support module `webtester-support-testng` provides a custom TestNG Listener.
5+
It has the following features:
6+
7+
- Life cycle management of class and test level `Browser` instances.
8+
- Automatic navigation to an entry point to the application under test before each test.
9+
- Injection of custom configuration properties into the following basic types: `String`, `Integer`, `Long`, `Float`, `Double` and `Boolean`
10+
11+
## Test Listener Life Cycle
12+
The `WebTesterTestNGListener` extends TestNG's normal life cycle at certain points.
13+
The following shows the workflow of a test class with two test methods.
14+
15+
- static `Browser` creation and injection
16+
- injection of configuration properties into static fields annotated with `@ConfigurationValue`
17+
- static methods annotated with `@BeforeClass`
18+
- instance `Browser` creation and injection
19+
- injection of configuration properties into instance fields annotated with `@ConfigurationValue`
20+
- instance methods annotated with `@BeforeMethod`
21+
- test method 1
22+
- instance methods annotated with `@AfterMethod`
23+
- instance `Browsers` are closed
24+
- instance `Browser` creation and injection
25+
- injection of configuration properties into instance fields annotated with `@ConfigurationValue`
26+
- instance methods annotated with `@BeforeMethod`
27+
- test method 2
28+
- instance methods annotated with `@AfterMethod`
29+
- instance `Browsers` are closed
30+
- static methods annotated with `@AfterClass`
31+
- static `Browsers` are closed
32+
33+
## Browser Life Cycle Management
34+
All `Browser's` life cycle is managed on class as well as test level (static / non static fields).
35+
To use this feature simply declare a `Browser` field in your test class and annotate it with `@Resource`.
36+
Every uninitialized (null) field annotated in that way will be injected with a new `Browser` instance.
37+
Fields which are already initialized with a `Browser` will be included in the life cycle handling as well,
38+
but no new instances are created by the runner.
39+
40+
### Example
41+
```java
42+
@Listeners(WebTesterTestNGListener.class)
43+
public class DifferentBrowserFieldModifiersTest {
44+
45+
// A pre-initialized Browser which will not be initialized with a new
46+
// browser but the instance will be handled as part of the life cycle.
47+
@Resource
48+
static Browser preInitializedBrowser = new Browser(new FirefoxDriver());
49+
50+
// A static Browser which will be initialized with a new instance before
51+
// the first and closed after the last test is executed.
52+
@Resource
53+
@CreateUsing ( ... )
54+
static Browser classScopedBrowser;
55+
56+
// An instance Browser which will be initialized with a new instance
57+
// before and closed after each test is executed.
58+
@Resource
59+
@CreateUsing ( ... )
60+
Browser testScopedBrowser;
61+
62+
// An instance Browser field which will be ignored by the runner since
63+
// the @Resource annotation is missing.
64+
Browser notAManagedBrowser;
65+
66+
...
67+
68+
}
69+
```
70+
71+
## @CreateUsing
72+
In order to configure the `BrowserFactory` used to create the `Browser` instances, the `@CreateUsing`
73+
annotation must be used.
74+
75+
### Example
76+
```java
77+
@Listeners(WebTesterTestNGListener.class)
78+
public class DifferentBrowserFactoriesTest {
79+
80+
// Uses the FirefoxFactory to create Firefox instances.
81+
@Resource
82+
@CreateUsing ( FirefoxFactory.class )
83+
static Browser firefox;
84+
85+
// Uses the InternetExplorerFactoryto create IE instances.
86+
@Resource
87+
@CreateUsing ( InternetExplorerFactory.class )
88+
Browser internetExplorer;
89+
90+
...
91+
92+
}
93+
```
94+
95+
## @EntryPoint
96+
In order for a `Browser` to be automatically navigated to an applications entry point before each test,
97+
the `@EntryPoint` annotation can used. The navigation at the beginning of each test is done weather or
98+
not a `Browser` is static!
99+
100+
### Example
101+
```java
102+
@Listeners(WebTesterTestNGListener.class)
103+
public class EntryPointsTest {
104+
105+
// Will begin each test on Google.
106+
@Resource
107+
@CreateUsing ( ... )
108+
@EntryPoint ( "http://www.google.com" )
109+
static Browser classScopedBrowser;
110+
111+
// Will begin each test on Bing.
112+
@Resource
113+
@CreateUsing ( ... )
114+
@EntryPoint ( "http://www.bing.com" )
115+
Browser testScopedBrowser;
116+
117+
...
118+
119+
}
120+
```
121+
122+
## Configuration Property Injection
123+
All custom configuration properties can be injected into the following base field types:
124+
`String`, `Integer`, `Long`, `Float`, `Double` and `Boolean`.
125+
126+
The injection is done for all fields which are annotated with `@ConfigurationValue`.
127+
128+
### Example
129+
```java
130+
@Listeners(WebTesterTestNGListener.class)
131+
public class ConfigurationValuesTest {
132+
133+
// Injects the integer value of "customer.integer"
134+
@ConfigurationValue ( "custom.integer" )
135+
static Integer customInteger;
136+
137+
// Injects the string value of "customer.string"
138+
@ConfigurationValue ( "custom.string" )
139+
String customString;
140+
141+
...
142+
143+
}
144+
```
145+
146+
## Multiple Browser Instances and Configuration Property Injection
147+
Since every `Browser` has it's own `Configuration` instance a "primary" Browser has to be declared when
148+
using multiple `Browser` instances and the `Configuration` property injection feature. The primary browser
149+
will be the source for the configuration properties injected by the `WebTesterTestNGListener`. If only one
150+
browser is managed it is automatically used as the primary browser!
151+
152+
**Note:** In case you want to inject property values into a static field your primary browser has to be
153+
static as well!
154+
155+
### Example
156+
```java
157+
@Listeners(WebTesterTestNGListener.class)
158+
public class MultiBrowserConfigurationValuesTest {
159+
160+
@Primary
161+
@Resource
162+
@CreateUsing ( ... )
163+
static Browser primaryBrowser;
164+
165+
@Resource
166+
@CreateUsing ( ... )
167+
Browser anotherBrowser;
168+
169+
@ConfigurationValue ( "custom.integer" )
170+
static Integer customInteger;
171+
172+
@ConfigurationValue ( "custom.string" )
173+
String customString;
174+
175+
...
176+
177+
}
178+
```
179+
180+
# Linked Documentation
181+
182+
- [Browser](browser.md)
183+
- [Configuration](configuration.md)

webtester-support-testng/src/main/java/info/novatec/testit/webtester/testng/listener/WebTesterTestNGListener.java

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package info.novatec.testit.webtester.testng.listener;
22

3-
43
import java.lang.reflect.Field;
54
import java.lang.reflect.Method;
65
import java.lang.reflect.Modifier;
@@ -22,6 +21,9 @@
2221
import info.novatec.testit.webtester.api.config.Configuration;
2322
import info.novatec.testit.webtester.internal.ReflectionUtils;
2423
import info.novatec.testit.webtester.testng.annotations.ConfigurationValue;
24+
import info.novatec.testit.webtester.testng.annotations.CreateUsing;
25+
import info.novatec.testit.webtester.testng.annotations.EntryPoint;
26+
import info.novatec.testit.webtester.testng.annotations.Primary;
2527
import info.novatec.testit.webtester.testng.exceptions.NoManagedBrowserException;
2628
import info.novatec.testit.webtester.testng.exceptions.NoPrimaryBrowserException;
2729
import info.novatec.testit.webtester.testng.exceptions.NoUniquePrimaryBrowserException;
@@ -33,6 +35,75 @@
3335
import info.novatec.testit.webtester.testng.listener.internal.WebTesterTestNGListenerAdapter;
3436

3537

38+
/**
39+
* This {@link org.testng.ITestNGListener} takes care of the following
40+
* life cycle management issues:
41+
* <ul>
42+
* <li>Creating {@link Browser browsers} for tests.</li>
43+
* <li>Injecting {@link Browser browser} instances into static and instance
44+
* fields of the test.</li>
45+
* <li>Injection of configuration properties into static and instance fields.
46+
* </li>
47+
* <li>Closing {@link Browser browsers} at the end of their natural scope.</li>
48+
* </ul>
49+
* More precisely, any {@link Field field} of type {@link Browser browser}
50+
* annotated with {@link Resource @Resource} and a value of <code>null</code>
51+
* will have a new {@link Browser browser} instance injected. Non
52+
* <code>null</code> fields which are annotated with {@link Resource @Resource}
53+
* will still be managed, but the original {@link Browser browser} instance will
54+
* be used. The {@link Browser browser} instances are created by using the
55+
* factory provided with the {@link CreateUsing @CreateUsing} annotation.
56+
* <p>
57+
* Fields annotated with {@link ConfigurationValue @ConfigurationValue} will be
58+
* injected with values from the primary browser's configuration. In case you
59+
* are using more then one browser, {@link Primary @Primary} has to be used to
60+
* declare one of them as the primary browser.
61+
* <p>
62+
* All of these operations are done regardless of field visibility (private,
63+
* default, protected or public). Reflection is used to break open all
64+
* visibility modifiers.
65+
* <p>
66+
* <b>Exaple test class:</b>
67+
* <pre>
68+
* <code>
69+
* public class FooTest {
70+
*
71+
* &#64;Resource
72+
* &#64;CreateUsing(FooBrowserFactory.class)
73+
* &#64;EntryPoint("http://localhost:8080/login")
74+
* private static Browser browser;
75+
*
76+
* &#64;ConfigurationValue("auth.username")
77+
* private String username;
78+
* &#64;ConfigurationValue("auth.password")
79+
* private String password;
80+
*
81+
* private HomePage home;
82+
*
83+
* &#64;Before
84+
* void executeLogin(){
85+
* home = browser.create(LoginPage.class).login(username, password);
86+
* }
87+
*
88+
* &#64;Test
89+
* void testFooOnHomePage(){
90+
* ...
91+
* }
92+
*
93+
* ...
94+
*
95+
* }
96+
* </code>
97+
* </pre>
98+
*
99+
* @see Browser
100+
* @see ConfigurationValue
101+
* @see CreateUsing
102+
* @see EntryPoint
103+
* @see Primary
104+
* @see Resource
105+
* @since 1.2
106+
*/
36107
public class WebTesterTestNGListener extends WebTesterTestNGListenerAdapter {
37108

38109
private List<ClassTestBrowser> classBrowsers = new ArrayList<>();
@@ -55,7 +126,7 @@ public void onStart(ITestContext iTestContext) {
55126

56127
private void initializeClassLevel(ITestContext iTestContext) {
57128
classBrowsers.clear();
58-
ITestNGMethod[] testMethods= iTestContext.getAllTestMethods();
129+
ITestNGMethod[] testMethods = iTestContext.getAllTestMethods();
59130
for (ITestNGMethod method : testMethods) {
60131
Class<?> testClass = method.getRealClass();
61132
for (Field field : ReflectionUtils.getAllFieldsOfClassHierarchy(testClass)) {
@@ -81,7 +152,7 @@ private void initializeClassLevel(ITestContext iTestContext) {
81152
*/
82153
private boolean fieldIsNoDuplicateOfAnExistingClassBrowserField(Field field) {
83154
boolean isNoDuplicate = true;
84-
for(Field classBrowserField : classBrowserFields) {
155+
for (Field classBrowserField : classBrowserFields) {
85156
if (classBrowserField.equals(field)) {
86157
isNoDuplicate = false;
87158
}
@@ -100,7 +171,7 @@ private void executeBeforeClassForAllBrowsers() {
100171
}
101172

102173
private void injectConfigurationValuesIntoStaticFields(ITestContext iTestContext) {
103-
ITestNGMethod[] testMethods= iTestContext.getAllTestMethods();
174+
ITestNGMethod[] testMethods = iTestContext.getAllTestMethods();
104175
for (ITestNGMethod method : testMethods) {
105176
Class<?> testClass = method.getRealClass();
106177
if (configurationValuesAnnotationIsUsedOnClassLevel(testClass)) {

0 commit comments

Comments
 (0)