如何使用@DataProvider将方法作为输入传递给@Test?

时间:2017-09-28 18:12:00

标签: testng

通过获取包中所有@DataProvider方法的列表并运行它们,我一直在编写检查@DataProviders失败的测试(因为这些测试被静默跳过)。这很好用,但是当我尝试使用@DataProvider(非常Meta,我知道)实现它时,我遇到了似乎是TestNG中的一个错误。在以下4个案例中,唯一有效的案例是封装的案例:

package mypackage;

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestDataProvidersWithMethod {

    //////////////// Plain example: Assertion fails

    @DataProvider(name = "TestThisDP")
    public Object[][] testThisDP() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP", (Class<?>[]) null);

        return new Object[][]{new Object[] {method}};
    }


    @Test(dataProvider = "TestThisDP")
    public void testGiveMethod(Method method) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        System.err.println("Method: " + method.getName());

        Assert.assertTrue(method.getName().equals("testThisDP")); // FAILS: name is actually "testGiveMethod" for some reason.
    }

    /////// Encapsulated example, this works, but has extra fluff


    class Container{
        public Method method;
        public Class clazz;

        public Container(Method method, Class clazz) {
            this.method = method;
            this.clazz = clazz;
        }
    }    

    @DataProvider(name = "TestThisDP4")
    public Object[][] testThisDP4() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP", (Class<?>[]) null);

        return new Object[][]{new Object[] {new Container(method,null)}};
    }

    @Test(dataProvider = "TestThisDP4")
    public void testGiveMethod(Container container) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        System.err.println("Method: " + container.method.getName());

        Assert.assertTrue(container.method.getName().equals("testThisDP")); // Succeeds!!
    }


    /////////////////// Weird failure, test isn't run due to TypeMismatch

    @DataProvider(name = "TestThisDP2")
    public Object[][] testThisDP2() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP2", (Class<?>[]) null);

        return new Object[][]{new Object[] {method ,""}};
    }


    @Test(dataProvider = "TestThisDP2")
    public void testGiveMethod2(Method method, String unused) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        System.err.println("Method: " + method.getName());

        Assert.assertTrue(method.getName().equals("testThisDP")); // FAILS hard: Type mismatch!!!
    }

    /////////////////////// Attempt at understanding the failure above..
    /////////////////////// This fails like the plain example, from the assertion

    @DataProvider(name = "TestThisDP3")
    public Object[][] testThisDP3() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP3", (Class<?>[]) null);

        return new Object[][]{new Object[] {"", method }};
    }


    @Test(dataProvider = "TestThisDP3")
    public void testGiveMethod3(String unused, Method method) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        System.err.println("Method: " + method.getName());

        Assert.assertTrue(method.getName().equals("testThisDP")); // FAILS: name is actually "testGiveMethod" for some reason.
    }
}

我做错了什么,或者这是TestNG中的错误?

1 个答案:

答案 0 :(得分:2)

这里没有错误。当您基本上Method作为@Test方法的参数之一时,TestNG基本上会尝试执行名为Native Injection的操作。

因此,在您的情况下,TestNG基本上是注入一个代表当前“被调用”Method方法的@Test引用。

要停用此Native Injection,您需要使用注释@NoInjection

以下是相同测试代码的固定版本

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.NoInjection;
import org.testng.annotations.Test;

import java.lang.reflect.Method;

public class TestDataProvidersWithMethod {

    //////////////// Plain example: Assertion fails

    @DataProvider(name = "TestThisDP")
    public Object[][] testThisDP() throws Exception {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP", (Class<?>[]) null);

        return new Object[][]{new Object[]{method}};
    }

    @Test(dataProvider = "TestThisDP")
    public void testGiveMethod(@NoInjection Method method) {
        System.err.println("Method: " + method.getName());
        // FAILS: name is actually "testGiveMethod" for some reason.
        Assert.assertEquals(method.getName(), "testThisDP");
    }

    /////// Encapsulated example, this works, but has extra fluff
    class Container {
        public Method method;
        public Class clazz;

        Container(Method method, Class clazz) {
            this.method = method;
            this.clazz = clazz;
        }

        @Override
        public String toString() {
            if (clazz == null) {
                return method.getName() + "()";
            }
            return clazz.getName() + "." + method.getName() + "()";
        }
    }

    @DataProvider(name = "TestThisDP4")
    public Object[][] testThisDP4() throws Exception {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP", (Class<?>[]) null);
        return new Object[][]{new Object[]{new Container(method, null)}};
    }

    @Test(dataProvider = "TestThisDP4")
    public void testGiveMethod(Container container) {
        System.err.println("Method: " + container.method.getName());
        // Succeeds!!
        Assert.assertEquals(container.method.getName(), "testThisDP");
    }


    /////////////////// Weird failure, test isn't run due to TypeMismatch

    @DataProvider(name = "TestThisDP2")
    public Object[][] testThisDP2() throws Exception {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP2", (Class<?>[]) null);
        return new Object[][]{new Object[]{method, ""}};
    }


    @Test(dataProvider = "TestThisDP2")
    public void testGiveMethod2(@NoInjection Method method, String unused) {
        System.err.println("Method: " + method.getName());
        // FAILS hard: Type mismatch!!!
        Assert.assertEquals(method.getName(), "testThisDP2");
    }

    /////////////////////// Attempt at understanding the failure above..
    /////////////////////// This fails like the plain example, from the assertion

    @DataProvider(name = "TestThisDP3")
    public Object[][] testThisDP3() throws Exception {
        Class<?> aclass = this.getClass();
        Method method = aclass.getMethod("testThisDP3", (Class<?>[]) null);
        return new Object[][]{new Object[]{"", method}};
    }

    @Test(dataProvider = "TestThisDP3")
    public void testGiveMethod3(String unused, @NoInjection Method method) {
        System.err.println("Method: " + method.getName());
        // FAILS: name is actually "testGiveMethod" for some reason.
        Assert.assertEquals(method.getName(), "testThisDP3");
    }

}

对于不涉及@DataProviders的方案,您可以参考this链接了解Native Injection的有效组合。