-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an API for custom test method parameter injection #612
Comments
I don't want to use @dataProvider annotation. |
Why don't you want to use @dataProvider, it's the easiest approach by far Cédric On Tue, Mar 3, 2015 at 6:09 AM, Crazyjavahacking notifications@github.com
|
The problem is that the object I want to inject is dynamically created based on the data inside annotations on test method. In my initial example, I need to parse the content of |
What is stopping you from doing all that in the data provider? Cédric On Tue, Mar 3, 2015 at 3:12 PM, Crazyjavahacking notifications@github.com
|
The functionality is not really parameterized testing and I also don't want to use data providers, e.g.:
so I don't think data providers are a good approach here |
Would be very useful I have the same needs |
The idea is interesting but as @cbeust said a long time ago, a data provider is a good workaround. @Columns("col1 | col2 || val)")
@Rows( {"a | b || c",
"d | e || f"})
@Test(dataProvider = "dp")
public void test1(MyCustomObject val) {
// MyCustomerObject is created from the annotation values
// some menipulation with val ...
}
@Columns("col1 | col2 || val)"
@Rows( {"1 | 2 || a",
"3 | 3 || b"})
@Test(dataProvider = "dp")
public void test1(MyCustomObject val) {
// MyCustomerObject is created from the annotation values
// some menipulation with val ...
}
@DataProvider
public static MyCustomObject[] dp(Method m) {
Columns colums = m.getAnnotation(Columns.class);
Rows rows = m.getAnnotation(Rows.class);
MyCustomObject[] results = new MyCustomObject[rows.values().length];
for (int i=0; i < rows.values().length; i++) {
String value = rows.values()[i];
// extract params with custom business
results[i] = new MyCustomObject(/* params */);
}
return results;
} |
this is true @juherr, i ended doing it this way. But, the only thing that misses is the abilitty to set a default dataProvider for all tests, in my case, my data provider is generics and passes only if there is certain annotations i think that a combination of the dataProvider and adding the ability to set a default provider or provider class would do the trick and will open a hole new possibilities |
@g13013 You mean something like public class UseMyDataProvider implements IAnnotationTransformer {
public void transform(ITest annotation, Class testClass, Constructor testConstructor, Method testMethod) {
if (/* business logic (for example: testMethod has expected annotations) */) {
annotation.setDataProviderClass(MyExternalClassWithDataProvider.class);
annotation.setDataProvider("dataprovider name");
}
}
} |
I would also love to be able to use Guice to inject parameters in tests. |
@gjuillot It could be a feature request. Could you open an issue with that? |
I'll do. But still, the best ever for me would be to have the possibility to use Guice to inject parameters in tests. |
Here's a proof of concept for injecting the parameters. The limitation is it does not support diff --git a/testng-core/src/main/java/org/testng/internal/Parameters.java b/testng-core/src/main/java/org/testng/internal/Parameters.java
index 701de725..2856e0f1 100644
--- a/testng-core/src/main/java/org/testng/internal/Parameters.java
+++ b/testng-core/src/main/java/org/testng/internal/Parameters.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.*;
+import com.google.inject.Injector;
import org.testng.DataProviderHolder;
import org.testng.IDataProviderInterceptor;
import org.testng.IDataProviderListener;
@@ -346,9 +347,9 @@ public class Parameters {
return new Object[0];
}
- if (areAllOptionalValuesNull(optionalValues)) {
- checkParameterTypes(method.getName(), parameterTypes, methodAnnotation, parameterNames);
- }
+// if (areAllOptionalValuesNull(optionalValues)) {
+// checkParameterTypes(method.getName(), parameterTypes, methodAnnotation, parameterNames);
+// }
List<Object> vResult = Lists.newArrayList();
List<Object> consParams =
@@ -388,7 +389,7 @@ public class Parameters {
}
private static boolean canInject(String annotation) {
- return !("@" + Test.class.getSimpleName()).equalsIgnoreCase(annotation);
+ return true;
}
private static final List<Class<?>> INJECTED_TYPES =
diff --git a/testng-core/src/main/java/org/testng/internal/objects/GuiceBasedObjectDispenser.java b/testng-core/src/main/java/org/testng/internal/objects/GuiceBasedObjectDispenser.java
index 1f036222..b5d34145 100644
--- a/testng-core/src/main/java/org/testng/internal/objects/GuiceBasedObjectDispenser.java
+++ b/testng-core/src/main/java/org/testng/internal/objects/GuiceBasedObjectDispenser.java
@@ -49,6 +49,9 @@ class GuiceBasedObjectDispenser implements IObjectDispenser {
if (injector == null) {
return null;
}
+ if (ctx != null) {
+ ctx.setAttribute(GUICE_INJECTOR, injector);
+ }
if (sa.getRawClass() == null) {
return injector.getInstance(sa.getTestClass().getRealClass());
} else {
diff --git a/testng-core/src/main/java/org/testng/internal/objects/IObjectDispenser.java b/testng-core/src/main/java/org/testng/internal/objects/IObjectDispenser.java
index 94f66393..6b2b82d5 100644
--- a/testng-core/src/main/java/org/testng/internal/objects/IObjectDispenser.java
+++ b/testng-core/src/main/java/org/testng/internal/objects/IObjectDispenser.java
@@ -9,6 +9,7 @@ import org.testng.internal.objects.pojo.CreationAttributes;
public interface IObjectDispenser {
String GUICE_HELPER = "testng.guice-helper";
+ String GUICE_INJECTOR = "testng.guice-injector";
Object dispense(CreationAttributes attributes);
diff --git a/testng-core/src/main/java/org/testng/internal/reflect/ReflectionRecipes.java b/testng-core/src/main/java/org/testng/internal/reflect/ReflectionRecipes.java
index 4b7eda5d..98468f3e 100644
--- a/testng-core/src/main/java/org/testng/internal/reflect/ReflectionRecipes.java
+++ b/testng-core/src/main/java/org/testng/internal/reflect/ReflectionRecipes.java
@@ -3,12 +3,16 @@ package org.testng.internal.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
+import java.lang.reflect.Type;
import java.util.*;
+import com.google.inject.Injector;
+import com.google.inject.Key;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestNGException;
import org.testng.annotations.NoInjection;
import org.testng.internal.RuntimeBehavior;
+import org.testng.internal.objects.IObjectDispenser;
import org.testng.xml.XmlTest;
/**
@@ -355,13 +359,14 @@ public final class ReflectionRecipes {
if (filters == null || filters.isEmpty()) {
return args;
}
+ Injector injector = context == null ? null : (Injector) context.getAttribute(IObjectDispenser.GUICE_INJECTOR);
final ArrayList<Object> arguments = new ArrayList<>(args.length);
final ListBackedImmutableQueue<Object> queue = new ListBackedImmutableQueue<>(args);
boolean firstMethodInjected = false;
for (final Parameter parameter : parameters) {
boolean inject = false;
- Object injectObject = null;
for (final InjectableParameter injectableParameter : filters) {
+ Object injectObject = null;
inject = canInject(parameter, injectableParameter);
if (inject) {
switch (injectableParameter) {
@@ -391,6 +396,16 @@ public final class ReflectionRecipes {
}
}
}
+ if (!inject && injector != null) {
+ try {
+ Type parameterizedType = parameter.getParameterizedType();
+ Object injectObject = injector.getInstance(Key.get(parameterizedType));
+ arguments.add(injectObject);
+ inject = true;
+ } catch (Exception e) {
+ // ignore
+ }
+ }
if (!inject && !queue.backingList.isEmpty()) {
arguments.add(queue.poll());
diff --git a/testng-core/src/test/java/test/guice/Guice1Test.java b/testng-core/src/test/java/test/guice/Guice1Test.java
index 75e5bc09..ec250f3c 100644
--- a/testng-core/src/test/java/test/guice/Guice1Test.java
+++ b/testng-core/src/test/java/test/guice/Guice1Test.java
@@ -11,6 +11,16 @@ public class Guice1Test extends SimpleBaseTest {
@Inject ISingleton m_singleton;
+ @Test
+ public void injectParam(ISingleton singleton) {
+ System.out.println("singleto1n = " + singleton);
+ }
+
+ @Test
+ public void injectParam2(ISingleton singleton) {
+ System.out.println("singleton1 = " + singleton);
+ }
+
@Test
public void singletonShouldWork() {
m_singleton.doSomething(); |
I need a way to inject a custom parameter into TestNG's test methods. The parameter is my own object constructed dynamically at runtime from test method annotations. The custom parameter is not known to TestNG, it's my own type, e.g.:
It looks like right now I cannot do it easily.
Can we add such functionality/SPI? What is the current easiest way to achieve that?
The text was updated successfully, but these errors were encountered: