防止TestNg在并行测试之间共享数据

防止TestNg在并行测试之间共享数据,testng,Testng,目标:独立并行运行两个类,其中每个测试将方法名存储到一个变量中,该变量可在稍后的测试中访问 问题:当测试并行运行时,它们开始在彼此之间共享数据,从而破坏测试 如果您看到控制台输出,这是错误的: INFO: Name of Test from Before Method: classB_Method1 INFO: Name of Test from Before Method: classB_Method1 因为这是两个独立的类,所以正在运行方法。及 我在这里设置了正确的名称: !! Set

目标:独立并行运行两个类,其中每个测试将方法名存储到一个变量中,该变量可在稍后的测试中访问

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

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

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
TestA

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(); 

    }
}

TestB

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 -->

有不同的方法来解决这个问题。我能想到的一个解决方案是Java的ThreadLocal概念。请参见此链接以获取示例-
(请参阅LocalDriverManager类)

您的SeleniumHelperDebug类是静态的,因此不是线程安全的。是否有任何原因使您不能在每个测试中拥有一个实例

您试图用SeleniumHelperDebug类解决什么问题

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

我的建议:

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");
    ....
@DataProvider(name=“testdata”)
公共静态对象[][]getTestData(ITestContext上下文)
{
列表测试=context.getSuite().getXmlSuite().getTests();
Map suiteParams=context.getSuite().getXmlSuite().getAllParameters();
Object[][]testData=新对象[tests.size()][2];
int i=0;
对于(XmlTest thisTest:tests){
testData[i][0]=新的FirefoxDriver();
testData[i][1]=thisTest.getName();
i++;
log(i+):添加了测试:“+thisTest.getName(),true);
}
返回测试数据;
}
....
@测试(dataProvider=“testdata”,dataProviderClass=testdata.class)
public void test2(FirefoxDriver se,字符串testName){
log(“Thread-”+Thread.currentThread().getId());
东南航行(”http://google.com");
....

很好的反馈Robbie。我没有将它们设置为静态的具体原因。我对Java相当陌生,并且一直在互联网上遵循示例。SeleniumHelperDebug类可以帮助测试,比如说,使用语法Classname\u MethodName\u Timestamp.png创建失败测试的屏幕截图,使用实例而不是stati.png也是如此c保证线程安全?因为它似乎解决了我的问题可以使用静态类,但您需要将驱动程序作为参数传递给MethodsHanks以获取注释。我看到了该示例,但对实现没有100%的把握。Robbie的反馈似乎解决了设置名称方法的问题,尽管我不确定它是否会我测试的每一个例子都是我的
@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");
    ....