理想情况下,最简单的方法是:
- 定义一个抽象类,您可以在其中定义所需的数据提供者以及数据提供者将从中获取的数据,作为其源并将其提供给测试方法(这可能类似于数据提供者从注入的值中获取进去)
- 拥有您的测试类,扩展这个抽象类,然后从
org.testng.IAnnotationTransformer
实现中,您只需将数据提供者方法名称注入测试类。
如果您也不想使用抽象类,那么这是另一种选择。这种看起来像是一种迂回的做法。
对于这个例子,我使用的依赖注入框架是 Guice。
我们将在此示例中使用的接口如下
/**
* Lets any test class expose the injected values to any caller.
*/
public interface ObjectGetter {
/**
* @return - The {@link Student} object that is required.
*/
Student getStudent();
}
/**
* Allows for setting the actual object to be used by any data provider
*/
public interface ObjectSetter {
/**
* @param student - The {@link Student} object
*/
void setStudent(Student student);
}
这是我们在这个例子中使用的 Guice 模块的样子
import com.google.inject.Binder;
import com.google.inject.Module;
public class MyLocalGuiceModule implements Module {
@Override
public void configure(Binder binder) {
binder.bind(Student.class).toInstance(new Student(100, "KungFu-Panda"));
}
}
这是测试类的样子
import com.google.inject.Inject;
import static org.assertj.core.api.Assertions.assertThat;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@Guice(modules = MyLocalGuiceModule.class)
public class SampleTestClass implements ObjectGetter {
@Inject
private Student student;
@Override
public Student getStudent() {
return student;
}
@Test
public void testMethod(Student s) {
String text = s.toString();
assertThat(text).isEqualTo("Student{id=100, name='KungFu-Panda'}");
}
}
下面是单独的数据提供者类的样子
import org.testng.annotations.DataProvider;
public class DataProviderHouse implements ObjectSetter {
private Student student;
@DataProvider(name = "students")
public Object[][] getStudents() {
return new Object[][]
{
{student}
};
}
@Override
public void setStudent(Student student) {
this.student = student;
}
}
注释转换器如下所示:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
public class LocalTransformer implements IAnnotationTransformer {
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor,
Method testMethod) {
annotation.setDataProviderClass(DataProviderHouse.class);
annotation.setDataProvider("students");
}
}
数据提供者侦听器如下所示:
import org.testng.IDataProviderListener;
import org.testng.IDataProviderMethod;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
public class DataProviderListener implements IDataProviderListener {
@Override
public void beforeDataProviderExecution(IDataProviderMethod dataProviderMethod,
ITestNGMethod method, ITestContext iTestContext) {
Object dpInstance = dataProviderMethod.getInstance();
if (!(dpInstance instanceof ObjectSetter)) {
return;
}
Object testInstance = method.getInstance();
if (!(testInstance instanceof ObjectGetter)) {
return;
}
((ObjectSetter) dpInstance).setStudent(((ObjectGetter) testInstance).getStudent());
}
}
这是套件 xml 的样子
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="dynamic_data_provider_suite" verbose="2">
<listeners>
<listener class-name="com.rationaleemotions.dynamic.LocalTransformer"/>
<listener class-name="com.rationaleemotions.dynamic.DataProviderListener"/>
</listeners>
<test name="dynamic_data_provider_test" verbose="2">
<classes>
<class name="com.rationaleemotions.dynamic.SampleTestClass"/>
</classes>
</test>
</suite>
以下是预计会发生的一系列事件:
- 测试类使用一个 Guice 模块,它将所需的依赖项注入到测试类中。
- 测试类通过接口向任何调用者(在本例中为数据提供者监听器)公开注入的依赖项
com.rationaleemotions.dynamic.ObjectGetter
- 我们有一个实现
org.testng.IAnnotationTransformer
,我们将数据提供者类和方法引用注入到测试方法中。
- 数据提供者类是一个单独的类,
com.rationaleemotions.dynamic.ObjectSetter
它使用它来获取它应该用于数据驱动测试的数据。
- 我们创建了一个实现
org.testng.IDataProviderListener
,TestNG 提供该实现来窃听数据提供者的调用事件之前和之后。使用这个监听器,我们从测试类中提取 Guice 注入的数据,然后将其注入到数据提供者所属的对象中。
这样做的方法有点长,但更有助于使数据提供者真正动态化。
您的使用里程可能会根据您希望采用这种“复杂但复杂的方法”的实际用例而有所不同。