Skip to content

Commit db7b66a

Browse files
committed
performance enhancements when dealing with large numbers of methods. issue testng-team#772
2 parents 6768e00 + 94b2285 commit db7b66a

File tree

4 files changed

+95
-61
lines changed

4 files changed

+95
-61
lines changed

src/main/java/org/testng/TestClass.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,55 +122,65 @@ public void addInstance(Object instance) {
122122
private void initMethods() {
123123
ITestNGMethod[] methods = m_testMethodFinder.getTestMethods(m_testClass, m_xmlTest);
124124
m_testMethods = createTestMethods(methods);
125-
125+
// moving these out of the loops reduces creation time of the methods from 196 seconds to 2 seconds under extreme circumstances
126+
ITestNGMethod[] beforeSuiteMethods = m_testMethodFinder.getBeforeSuiteMethods(m_testClass);
127+
ITestNGMethod[] afterSuiteMethods = m_testMethodFinder.getAfterSuiteMethods(m_testClass);
128+
ITestNGMethod[] beforeTestConfMethods = m_testMethodFinder.getBeforeTestConfigurationMethods(m_testClass);
129+
ITestNGMethod[] afterTestConfMethods = m_testMethodFinder.getAfterTestConfigurationMethods(m_testClass);
130+
ITestNGMethod[] beforeClassMethods = m_testMethodFinder.getBeforeClassMethods(m_testClass);
131+
ITestNGMethod[] afterClassMethods = m_testMethodFinder.getAfterClassMethods(m_testClass);
132+
ITestNGMethod[] beforeGroupsMethods = m_testMethodFinder.getBeforeGroupsConfigurationMethods(m_testClass);
133+
ITestNGMethod[] afterGroupsMethods = m_testMethodFinder.getAfterGroupsConfigurationMethods(m_testClass);
134+
ITestNGMethod[] beforeTestMethods = m_testMethodFinder.getBeforeTestMethods(m_testClass);
135+
ITestNGMethod[] afterTestMethods = m_testMethodFinder.getAfterTestMethods(m_testClass);
126136
for (Object instance : m_iClass.getInstances(false)) {
127137
m_beforeSuiteMethods = ConfigurationMethod
128-
.createSuiteConfigurationMethods(m_testMethodFinder.getBeforeSuiteMethods(m_testClass),
138+
.createSuiteConfigurationMethods(beforeSuiteMethods,
129139
m_annotationFinder,
130140
true,
131141
instance);
132142
m_afterSuiteMethods = ConfigurationMethod
133-
.createSuiteConfigurationMethods(m_testMethodFinder.getAfterSuiteMethods(m_testClass),
143+
.createSuiteConfigurationMethods(afterSuiteMethods,
134144
m_annotationFinder,
135145
false,
136146
instance);
137147
m_beforeTestConfMethods = ConfigurationMethod
138-
.createTestConfigurationMethods(m_testMethodFinder.getBeforeTestConfigurationMethods(m_testClass),
148+
.createTestConfigurationMethods(beforeTestConfMethods,
139149
m_annotationFinder,
140150
true,
141151
instance);
142152
m_afterTestConfMethods = ConfigurationMethod
143-
.createTestConfigurationMethods(m_testMethodFinder.getAfterTestConfigurationMethods(m_testClass),
153+
.createTestConfigurationMethods(afterTestConfMethods,
144154
m_annotationFinder,
145155
false,
146156
instance);
147157
m_beforeClassMethods = ConfigurationMethod
148-
.createClassConfigurationMethods(m_testMethodFinder.getBeforeClassMethods(m_testClass),
158+
.createClassConfigurationMethods(beforeClassMethods,
149159
m_annotationFinder,
150160
true,
151161
instance);
152162
m_afterClassMethods = ConfigurationMethod
153-
.createClassConfigurationMethods(m_testMethodFinder.getAfterClassMethods(m_testClass),
163+
.createClassConfigurationMethods(afterClassMethods,
154164
m_annotationFinder,
155165
false,
156166
instance);
157167
m_beforeGroupsMethods = ConfigurationMethod
158-
.createBeforeConfigurationMethods(m_testMethodFinder.getBeforeGroupsConfigurationMethods(m_testClass),
168+
.createBeforeConfigurationMethods(beforeGroupsMethods,
159169
m_annotationFinder,
160170
true,
161171
instance);
162172
m_afterGroupsMethods = ConfigurationMethod
163-
.createAfterConfigurationMethods(m_testMethodFinder.getAfterGroupsConfigurationMethods(m_testClass),
173+
.createAfterConfigurationMethods(afterGroupsMethods,
164174
m_annotationFinder,
165175
false,
166176
instance);
167177
m_beforeTestMethods = ConfigurationMethod
168-
.createTestMethodConfigurationMethods(m_testMethodFinder.getBeforeTestMethods(m_testClass),
178+
.createTestMethodConfigurationMethods(beforeTestMethods,
169179
m_annotationFinder,
170180
true,
171181
instance);
172182
m_afterTestMethods = ConfigurationMethod
173-
.createTestMethodConfigurationMethods(m_testMethodFinder.getAfterTestMethods(m_testClass),
183+
.createTestMethodConfigurationMethods(afterTestMethods,
174184
m_annotationFinder,
175185
false,
176186
instance);

src/main/java/org/testng/internal/BaseTestMethod.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -396,40 +396,44 @@ public boolean canRunFromClass(IClass testClass) {
396396
return m_methodClass.isAssignableFrom(testClass.getRealClass());
397397
}
398398

399-
/**
400-
* {@inheritDoc} Compares two BaseTestMethod using the test class then the associated
401-
* Java Method.
402-
*/
403399
@Override
404-
public boolean equals(Object obj) {
405-
if (this == obj) {
406-
return true;
407-
}
408-
if (obj == null) {
409-
return false;
410-
}
411-
if (getClass() != obj.getClass()) {
412-
return false;
413-
}
414-
415-
BaseTestMethod other = (BaseTestMethod) obj;
416-
417-
boolean isEqual = m_testClass == null ? other.m_testClass == null
418-
: other.m_testClass != null &&
419-
m_testClass.getRealClass().equals(other.m_testClass.getRealClass())
420-
&& m_instance == other.getInstance();
421-
422-
return isEqual && getConstructorOrMethod().equals(other.getConstructorOrMethod());
423-
}
400+
public boolean equals(Object obj) {
401+
if (this == obj)
402+
return true;
403+
if (obj == null)
404+
return false;
405+
if (getClass() != obj.getClass())
406+
return false;
407+
BaseTestMethod other = (BaseTestMethod) obj;
408+
if (m_instance == null) {
409+
if (other.m_instance != null)
410+
return false;
411+
} else if (!m_instance.equals(other.m_instance))
412+
return false;
413+
if (m_method == null) {
414+
if (other.m_method != null)
415+
return false;
416+
} else if (!m_method.equals(other.m_method))
417+
return false;
418+
if (m_testClass == null) {
419+
if (other.m_testClass != null)
420+
return false;
421+
} else if (!m_testClass.equals(other.m_testClass))
422+
return false;
423+
return true;
424+
}
424425

425-
/**
426-
* {@inheritDoc} This implementation returns the associated Java Method's hash code.
427-
* @return the associated Java Method's hash code.
428-
*/
429426
@Override
430-
public int hashCode() {
431-
return m_method.hashCode();
432-
}
427+
public int hashCode() {
428+
final int prime = 31;
429+
int result = 1;
430+
result = prime * result
431+
+ ((m_instance == null) ? 0 : m_instance.hashCode());
432+
result = prime * result + ((m_method == null) ? 0 : m_method.hashCode());
433+
result = prime * result
434+
+ ((m_testClass == null) ? 0 : m_testClass.hashCode());
435+
return result;
436+
}
433437

434438
protected void initGroups(Class<? extends ITestOrConfiguration> annotationClass) {
435439
//

src/main/java/org/testng/internal/Graph.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public void topologicalSort() {
115115
for (Node<T> n : getNodes()) {
116116
if (! isIndependent(n.getObject())) {
117117
ppp("ADDING FOR SORT: " + n.getObject());
118-
nodes2.add(n.clone());
118+
nodes2.add(n);
119119
}
120120
else {
121121
ppp("SKIPPING INDEPENDENT NODE " + n);
@@ -287,15 +287,17 @@ public Map<T, T> getPredecessors() {
287287
public boolean removePredecessor(T o) {
288288
boolean result = false;
289289

290-
T pred = m_predecessors.get(o);
291-
if (null != pred) {
292-
result = null != m_predecessors.remove(o);
293-
if (result) {
294-
ppp(" REMOVED PRED " + o + " FROM NODE " + m_object);
295-
}
296-
else {
297-
ppp(" FAILED TO REMOVE PRED " + o + " FROM NODE " + m_object);
298-
}
290+
if (!m_predecessors.isEmpty()) {
291+
T pred = m_predecessors.get(o);
292+
if (null != pred) {
293+
result = null != m_predecessors.remove(o);
294+
if (result) {
295+
ppp(" REMOVED PRED " + o + " FROM NODE " + m_object);
296+
}
297+
else {
298+
ppp(" FAILED TO REMOVE PRED " + o + " FROM NODE " + m_object);
299+
}
300+
}
299301
}
300302

301303
return result;

src/main/java/org/testng/internal/annotations/JDK15AnnotationFinder.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import org.testng.annotations.TestInstance;
4040
import org.testng.internal.collections.Pair;
4141

42+
import com.google.common.collect.Maps;
43+
4244
/**
4345
* This class implements IAnnotationFinder with JDK5 annotations
4446
*
@@ -97,16 +99,32 @@ private <A extends Annotation> A findAnnotationInSuperClasses(Class<?> cls, Clas
9799
return null;
98100
}
99101

100-
@Override
102+
private Map<Pair,IAnnotation> annotationCache = Maps.newConcurrentMap();
103+
private final static IAnnotation NULL_CACHE_ENTRY = new IAnnotation() {};
104+
@Override
101105
public <A extends IAnnotation> A findAnnotation(Method m, Class<A> annotationClass) {
102-
final Class<? extends Annotation> a = m_annotationMap.get(annotationClass);
103-
if (a == null) {
104-
throw new IllegalArgumentException("Java @Annotation class for '"
105-
+ annotationClass + "' not found.");
106-
}
107-
Annotation annotation = m.getAnnotation(a);
108-
return findAnnotation(m.getDeclaringClass(), annotation, annotationClass, null, null, m,
109-
new Pair<>(annotation, m));
106+
Pair<Method,Class<A>> cacheKey = new Pair<>(m,annotationClass);
107+
IAnnotation cachedValue = annotationCache.get(cacheKey);
108+
if (cachedValue == null) {
109+
final Class<? extends Annotation> a = m_annotationMap.get(annotationClass);
110+
if (a == null) {
111+
throw new IllegalArgumentException("Java @Annotation class for '"
112+
+ annotationClass + "' not found.");
113+
}
114+
Annotation annotation = m.getAnnotation(a);
115+
cachedValue = findAnnotation(m.getDeclaringClass(), annotation, annotationClass, null, null, m,
116+
new Pair<>(annotation, m));
117+
if (cachedValue == null) {
118+
cachedValue = NULL_CACHE_ENTRY;
119+
}
120+
annotationCache.put(cacheKey, cachedValue);
121+
}
122+
123+
if (cachedValue == NULL_CACHE_ENTRY) {
124+
return null;
125+
} else {
126+
return (A) cachedValue;
127+
}
110128
}
111129

112130
@Override

0 commit comments

Comments
 (0)