Java 利用现有测试体系结构的TestNG的困难

Java 利用现有测试体系结构的TestNG的困难,java,selenium-webdriver,testng,Java,Selenium Webdriver,Testng,下面是我的类结构的一个简单(最小)表示,请注意,结构中只有一个与TestNG的集成点(抽象类上的@Test注释) 现在,下面是一个测试用例的示例,它可以很好地使用上述结构 public class sampletest extends AbstractValidator2{ public sampletest() { super("www.google.com", null); } @Override public boolean validate

下面是我的类结构的一个简单(最小)表示,请注意,结构中只有一个与TestNG的集成点(抽象类上的@Test注释)

现在,下面是一个测试用例的示例,它可以很好地使用上述结构

public class sampletest extends AbstractValidator2{
    public sampletest() {
        super("www.google.com", null);
    }
    @Override
    public boolean validate() {
        return true;
    }
}
由于上面有一个无参数构造函数,所以它很容易与TestNG一起使用。我可以将其包含在任何测试xml文件中,并配置它以任何方式运行。太好了,生活是美好的

下面的下一个测试是与TestNG的集成

public class sampletest2 extends AbstractValidator2{
    Date date;
    public sampletest2(String url, Date date) {
        super(url, null);
        date = date;
    }
    @Override
    public boolean validate() {
        driver.get(url);
        Utils.wait(5000);
        return false;
    }
}
在本例中,我需要为构造函数提供参数。我还需要为我要测试的每个测试用例提供一个新实例。这就排除了单独使用数据提供者的可能性。为了增加复杂性,我还需要并行运行。工厂确实在工作,但有一个问题。在使用工厂时,我似乎不可能选择单个用例(我必须在不更改代码的情况下运行所有用例)。每天我都喜欢单独运行用例

我提出的解决方案如下

public class sampletest2suite {
    @Test
    public void sampletest2google(){
        new sampletest2("https://www.google.com/", null).run();
    }
    @Test
    public void sampletest3bing(){
        new sampletest2("https://www.bing.com/", null).run();
    }
}
然而,这种结构使我瘫痪,并创建了一种阻止我利用Testng的许多强大功能的结构。我的目标是利用testng的xml配置,以便从java类结构中删除重复的代码和配置

public class sampletest extends AbstractValidator2{
    public sampletest() {
        super("www.google.com", null);
    }
    @Override
    public boolean validate() {
        return true;
    }
}
我还提出了另一个解决办法。这个解决方案滥用继承性并生成子类的唯一原因是为了与testng兼容而提供一个无参数构造函数。关于为什么这是一个坏模式,您可以看到以下stackexchange问题:


鉴于目前的问题,有没有人有什么建议可以让你重新走上更健康的道路。

我认为TestNG有一些功能,如果使用的话,会让你的生活更轻松
setup()
tearDown()
应在*之前和之后适当地添加
@注释。这将触发它们在适当的时间运行,而不必在一些
run()
方法中调用它们。实例化驱动程序应该在
setup()
中。最佳做法是创建一个浏览器实例,将其用于一个测试,然后销毁它。这样可以保持每次运行的独立性,避免运行的交叉污染(一次运行变差,并扰乱后续运行等)

下面是一个简单的示例,我希望它能帮助您理解如何使用带有TestNG的数据提供程序来完成您想要的事情

public class TestNg
{
    private WebDriver driver;

    @Test(dataProvider = "getData")
    public void test(String url, String title)
    {
        driver.navigate().to(url);
        assertEquals(driver.getTitle(), title, "Verify title");
    }

    @BeforeMethod
    public void setup()
    {
        String chromeDriverPath = "C:\\path\\to\\chromedriver.exe";
        System.setProperty("webdriver.chrome.driver", chromeDriverPath);
        driver = new ChromeDriver();
    }

    @AfterMethod
    public void tearDown()
    {
        driver.close();
        driver.quit();
    }

    @DataProvider
    public Object[][] getData()
    {
        return new Object[][] { { "http://www.google.com", "Google" }, { "http://www.bing.com", "Bing" } };
    }
}

有很多方法可以使用TestNG来实现数据提供程序。这只是其中之一。你会更好地知道哪种方法可能适合你的需要,并且可以调查官方文件并选择适合你的方法。

这里有一种解决问题的方法

成分:

  • 表示要注入到每个测试中的参数的自定义注释
  • 每个测试变量都有一个基类(或者,您甚至可以有一个只处理对象的通用基类)
  • 在基类中实现
    IHookable
    实现,在确定要注入的正确参数后,该实现将扮演修补测试调用的角色
  • 一个对象工厂(如果需要的话),负责创建要实例化到测试中的对象(类似于Spring所做的)
  • 这是样品

    注释

    import java.lang.annotation.Retention;
    导入java.lang.annotation.Target;
    导入静态java.lang.annotation.ElementType.METHOD;
    导入静态java.lang.annotation.ElementType.TYPE;
    @保留(java.lang.annotation.RetentionPolicy.RUNTIME)
    @目标({方法,类型})
    公共@接口参数{
    字符串url()默认为“”;
    字符串getComplexClass()默认为“testngImplementation.acomplexclass”;
    }
    
    测试将从中扩展的基类

    import org.testng.IHookCallBack;
    导入org.testng.IHookable;
    导入org.testng.ITestResult;
    导入org.testng.internal.ClassHelper;
    导入java.util.ArrayList;
    导入java.util.List;
    公共类抽象验证器实现IHookable{
    公共抽象验证器(){
    //更常见的设置报告、selenium、实用程序等。。。
    }
    public void setup(){}
    public void拆卸(){}
    @凌驾
    公共无效运行(IHookCallBack回调、ITestResult testResult){
    println(“我们让它在抽象验证器2上运行”);
    设置();
    Object[]parameters=callBack.getParameters();
    对象[]已注入=getParametersToInject(testResult);
    if(parameters.length==injected.length){
    数组复制(注入,0,参数,0,参数,长度);
    }
    runTestMethod(testResult);
    撕裂();
    }
    私有对象[]getParametersToInject(ITestResult testResult){
    列表参数=新的ArrayList();
    注射参数=
    测试结果
    .getMethod()
    .getConstructorMethod()
    .getMethod()
    .getAnnotation(InjectParameters.class);
    如果(toInject!=null){
    add(toInject.url());
    add(ClassHelper.newInstance(ClassHelper.forName(toInject.getComplexClass()));
    }
    返回参数.toArray(新对象[0]);
    }
    }
    
    样本测试类

    公共类TestCreation扩展了AbstractValidator{
    @试验
    @内射参数(url=”https://www.google.com/")
    //@Parameters在这里用作占位符。为了防止触发TestNG
    //验证表明该参数是必需的,但未提供。我认为这将是固定的
    //作为修复的一部分https://github.com/cbeust/testng/issues/564 这将在
    //TestNG 7.0.0
    @参数({“url”,“a”})
    public void sampletest2google(@Optional String url,@Optional acomplexclass a){
    系统
    
    public class TestNg
    {
        private WebDriver driver;
    
        @Test(dataProvider = "getData")
        public void test(String url, String title)
        {
            driver.navigate().to(url);
            assertEquals(driver.getTitle(), title, "Verify title");
        }
    
        @BeforeMethod
        public void setup()
        {
            String chromeDriverPath = "C:\\path\\to\\chromedriver.exe";
            System.setProperty("webdriver.chrome.driver", chromeDriverPath);
            driver = new ChromeDriver();
        }
    
        @AfterMethod
        public void tearDown()
        {
            driver.close();
            driver.quit();
        }
    
        @DataProvider
        public Object[][] getData()
        {
            return new Object[][] { { "http://www.google.com", "Google" }, { "http://www.bing.com", "Bing" } };
        }
    }