【问题标题】:Prevent TestNg sharing data between parallel tests防止 TestNg 在并行测试之间共享数据
【发布时间】:2014-04-20 10:19:59
【问题描述】:

目标:并行独立运行 2 个类,其中每个测试将方法名称存储到一个变量中,以便稍后在测试中访问。

问题:当测试并行运行时,它们开始在彼此之间共享数据,从而破坏测试。

如果您看到控制台输出,这是错误的:

INFO: Name of Test from Before Method: classB_Method1
INFO: Name of Test from Before Method: classB_Method1

由于这是两个独立的类,并且正在运行的方法。和 我在这里设置了正确的名称:

  !! Setting Method name to: classA_Method1
    !! Setting Method name to: classB_Method1  

输出应如下所示:

INFO: Name of Test from Before Method: classA_Method1
INFO: Name of Test from Before Method: classB_Method1

测试A

import java.lang.reflect.Method;
import org.testng.annotations.*;
import com.xxxx.util.*;

public class TestA {


    @Test(/*dataProvider = "DP_MVPLoan_Login",*/ groups = {"parallel_test" }, invocationCount = 1, priority = 2, enabled = true)
    public void classA_Method1(/*String... excelData*/) throws Exception {

    }

    /////////////////////////////////////////////////////////////////////////////
    // ****SetUp and Tear Down

    @BeforeTest(alwaysRun=true)
    public void setupClass() throws Exception {
    }


    @BeforeMethod(alwaysRun=true)
    public void setupMethod(Method method) throws Exception {
        SeleniumHelperDebug.setCurrentMethodName(method.getName());
        SeleniumHelperDebug.defaultBeforeMethod(); 

    }

}

测试B

import java.lang.reflect.Method;
import org.testng.annotations.*;
import com.xxxx.util.*;

public class TestB {


@Test(/*dataProvider = "DP_MVPLoan_Login",*/ groups = { "parallel_test" }, invocationCount = 1, priority = 2, enabled = true)
public void classB_Method1(/*String... excelData*/) throws Exception {

}

/////////////////////////////////////////////////////////////////////////////
// ****SetUp and Tear Down

@BeforeTest(alwaysRun=true)
public void setupClass() throws Exception {
}


@BeforeMethod(alwaysRun=true)
public void setupMethod(Method method) throws Exception {
    SeleniumHelperDebug.setCurrentMethodName(method.getName());
    SeleniumHelperDebug.defaultBeforeMethod(); 

}

}

辅助方法

public class SeleniumHelperDebug { 



    //Name of the method/Test being run
    private static String currentMethodName;
    public static String getCurrentMethodName() {
        return currentMethodName;
    }
    public static void setCurrentMethodName(String currentMethodName) {
        System.out.println("!! Setting Method name to: "+ currentMethodName);
        SeleniumHelperDebug.currentMethodName = currentMethodName;
    }

    //Setup Method. BeforeTest
    public static void defaultBeforeMethod() throws Exception {
        Thread.sleep(500);
        /*setCurrentMethodName(method.getName());*/
        System.out.println("INFO: Name of Test from Before Method: " +getCurrentMethodName() );


        System.out.println("REMINDER: Keep Browser Window in Foreground to Help prevent F@ilures");
    }
}

Testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="classes" verbose="2" thread-count="2">

<!-- 
<listeners>
<listener class-name="com.progressfin.util.WebDriverListener"></listener>
</listeners -->>
<tests>
    <test name="Test" preserve-order="true">
        <!-- <parameter name="browserName" value="firefox"></parameter> -->

    <groups>
      <run>
        <include name="parallel_test"/>
      </run>
    </groups>


    <classes>

        <class name="com.xxxx.test.TestA" />
        <class name="com.xxxx.test.TestB"/>
    </classes>


    </test> <!-- Test -->
</tests>
</suite> <!-- Suite -->

控制台输出

...
... TestNG 6.8.6 by Cédric Beust (cedric@beust.com)
...

[TestNG] Running:
  C:\Users\samuel.safyan\workspace\JavaSelenium2\testNgParallelism2.xml

[TestRunner] Starting executor for test Test with time out:2147483647 milliseconds.
!! Setting Method name to: classA_Method1
!! Setting Method name to: classB_Method1
INFO: Name of Test from Before Method: classB_Method1
REMINDER: Keep Browser Window in Foreground to Help prevent F@ilures
INFO: Name of Test from Before Method: classB_Method1
REMINDER: Keep Browser Window in Foreground to Help prevent F@ilures
PASSED: classB_Method1
PASSED: classA_Method1

===============================================
    Test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

【问题讨论】:

    标签: testng


    【解决方案1】:

    您的 SeleniumHelperDebug 类是静态的,因此不是线程安全的。有什么理由不能让每个测试都有一个实例吗?

    您想用 SeleniumHelperDebug 类解决什么问题?

    可能有更好的解决方案是线程安全的,但不清楚该类试图实现什么

    【讨论】:

    • 良好的反馈罗比。我没有将它们设置为静态的具体原因。我对 Java 相当陌生,并且正在关注互联网上的示例。 SeleniumHelperDebug 类有助于测试,例如,使用语法 Classname_MethodName_Timestamp.png 创建失败测试的屏幕截图,那么使用实例而不是静态保证线程安全吗?因为它似乎解决了我的问题
    • 可以使用静态类,但您需要将驱动程序作为参数传递给方法
    【解决方案2】:

    我的建议:

    1.  Dont use static webdriver instances.
    2.  Dont use ThreadLocal
    

    那么答案是什么?

    Well, you don't need to handle the threads if your using a testrunner that can
    fork threads for you.  I use TestNG, and in that case I just pass DriverHelper
    objects as arguments into my test methods from  my Factory or my DataProvider 
    method.   The DataProvider creates multiple helper instances and then once the
    DriverHelper is inside my @Test annotated method, I instantiate the WebDriver 
    browser and proceed with test.   If my DataProvider returns 10 items, then 
    TestNG iterates it 10 times, each on a different thread.  Of course, this is
    overly simplified, because you need to pay attention to the test lifecycle, and
    take care to not open the browser until after you are in the Test method, but
    it should get you started.
    

    帮助您入门。这是一个无效的示例,作为提示:

    @DataProvider(name = "testdata")
    public static Object[][] getTestData( ITestContext context ) 
    {
        List<XmlTest> tests = context.getSuite().getXmlSuite().getTests();
        Map<String, String> suiteParams = context.getSuite().getXmlSuite().getAllParameters();
        Object[][] testData = new Object[tests.size()][2];
        int i = 0;
        for ( XmlTest thisTest : tests ) {
            testData[i][0] = new FirefoxDriver();
            testData[i][1] = thisTest.getName();
            i++;
            Reporter.log( i +  ": Added test: " + thisTest.getName(), true );
        }
        return testData;
    }
    ....
    @Test(dataProvider = "testdata", dataProviderClass = TestData.class)
        public void test2( FirefoxDriver se, String testName ) {
            Reporter.log("Thread-" + Thread.currentThread().getId() );
            se.navigateTo("http://google.com");
        ....
    

    【讨论】:

      【解决方案3】:

      有不同的方法来解决这个问题。我能想到的一种解决方案是 Java 的 ThreadLocal 概念。有关示例,请参见此链接 -http://rationaleemotions.wordpress.com/2013/07/31/parallel-webdriver-executions-using-testng/ (参见 LocalDriverManager 类)。

      【讨论】:

      • 感谢您的评论。我看到了那个例子,但不是 100% 确定实施。 Robbie 的反馈似乎已经解决了设置名称方法的问题,尽管我不确定它是否适用于我的测试中的每个示例
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多