TestNG

Нахрен CSV, давай парсить тест данные из json

CSV слишком простой и тупой для хранения данных тестов, предлагаю хранить эти данные в json, т.к. json огонь и его все любят.

1 Ставим json.simple через Maven:

<dependency>  
    <groupId>com.googlecode.json-simple</groupId>  
    <artifactId>json-simple</artifactId>  
    <version>1.1.1</version>  
</dependency>

2 Пишем метод, который принимает как сырые данные json формата, так и путь к .json файлу:

public static JSONObject parseJsonData(String data) throws ParseException, IOException {  
    boolean isJsonContent = data.substring(0, 1).matches("\\{");  
    Object object;  
    JSONParser parser = new JSONParser();  
    if (isJsonContent) object = parser.parse(data);  
    else object = parser.parse(new FileReader(data));  
    return (JSONObject) object;  
}

3 Он возвращает обьект типа JSONObject, с которым можно ковыряться удобными способами:

Object jsonRequests = jsonObject.get("Requests");  
  
int currentRequestId = 0;  
  
JSONObject request = (JSONObject) jsonRequests.get(currentRequestId);  
String requestName = (String) request.get("Name");  
JSONArray testCases = (JSONArray) request.get("TestCases");

Из JSONObject можно выковыривать любые данные, а с JSONArray работать как с обычным массивом.

Как через testng.xml передать параметр только одному методу?

На сайте нашел кучу любых методов передачи параметров из testng.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<suite name="ParameterSuite">  
  <parameter name="suiteParam" value="suiteScoped"></parameter>  
  <parameter name="commonParam" value="suiteValue"></parameter>  
  <test name="MethodParamScopedTest">  
    <parameter name="testParam" value="testScoped"></parameter>  
    <classes>  
      <parameter name="classesParam" value="classesScoped"></parameter>  
      <class name="com.javarticles.testng.TestClass1">  
        <parameter name="classParam" value="classScoped"></parameter>  
        <parameter name="commonParam" value="overridenClassValue"></parameter>  
      </class>  
      <class name="com.javarticles.testng.TestClass2"/>  
    </classes>  
  </test>  
</suite>

Но, что за подстава, самый глубокий из них передает параметры классу тестов, а как передать только одному методу? А вот как:

<test verbose="1" name="addCard" annotations="JDK" preserve-order="true">  
    <classes>  
        <class name="app.passenger.User">  
            <methods>  
                <include name="changeUserInfo"/>  
            </methods>  
        </class>  
        <class name="app.passenger.Payments">  
            <methods>  
                <include name="addCard"/>  
                <include name="addCard">  
                    <parameter name="testCase" value="Success2ndCard"/>  
                </include>  
            </methods>  
        </class>  
    </classes>  
</test>

Как передать параметр из Jenkins -> ANT -> TestNG

  1. В Jenkins идем в настройки Джоба и выставляем "This build is parameterized"
  2. Называем параметр "additionalScreens" например
  3. В ant.xml проставляем
    <property name="additionalScreens" value=""/>
    
  4. В ant.xml в таргете не забываем передать этот параметр в TestNG:
    <target name="Test.Real" depends="compile">  
            <testng outputdir="${testdir}" classpathref="all.classpath" haltOnFailure="true" testnames="Buy">  
                <xmlfileset dir="${basedir}" includes="${testngxml}"/>  
                <jvmarg value="-DadditionalScreens=${additionalScreens}" />  
            </testng>  
    </target>
    
  5. В TestNG.xml параметр никак не фигурирует, там просто вызывается тест:
    <test verbose="1" name="Buy" annotations="JDK">  
        <classes>  
            <class name="TestNG.Buy">  
                <methods>  
                    <include name="shop"/>  
                    <include name="Scan"/>  
                    <include name="Buy"/>  
                </methods>  
            </class>  
        </classes>  
    </test>
    
  6. В методе @BeforeClass принимаем параметр и дальше работаем с ним как хотим:
    @Parameters({ "additionalScreens" })  
        @BeforeClass  
        public void prepare(String additionalScreens, ITestContext context) throws Exception {  
            context.setAttribute("additionalScreens", additionalScreens);  
            //......  
    }
    
  7. Запускаем Джоб в Дженкинсе и заполняем или выбираем параметр "additionalScreens" - он передается в тест. Это может быть, например, урл сервера, или тип проверки, и т.д.
    Не благодари!

Как заставить выполняться @AfterClass в TestNG

Заметил, что метод @AfterClass не выполняется, если хоть один из тестов к классе завалился или пропущен. Так как заставить её выполняться, ведь там идет и driver.quit() и весь репортинг в стороннюю мониторинг систему?
Похоже на "Как высыпаться за 30 минут в день - читайте в моей новой книге "Никак, блядь".
Лучше сделаем из этого метода такой:

@AfterGroups("thisClassGroup")  
    public void report() throws Exception{  
        driver.quit();  
        if (Objects.equals(fullErrorMessage, "")) fullErrorMessage = "OK";  
        Log.report(fullErrorMessage, "thisClassGroup", finalErrorType);  
    }
А всем тест методам пропишем
@Test(description = "Test1", groups = "thisClassGroup")

Как получать данные из CSV для тестов на TestNG

В TestNG Есть клевая приблуда для предоставления данных тестам под названием DataProvider. Но удобнее ведь хранить данные во внешних файлах. Например, в случае .csv файла новый тест кейс таким образом создается тупо добавлением новой строчки в .csv таблицу. Написанный ниже DataProvider запускает тест каждый раз, как находит новую строчку в .csv файле, пропуская первую строчку, т.к. мы принимаем её за заголовок.

@DataProvider(name = "Data")  
    public Iterator<Object []> dataReader() throws InterruptedException {  
        List<Object []> dataLines = new ArrayList<>();  
        boolean notDataHeader = false;  
        String[] data;  
        BufferedReader br;  
        String line;  
        String workingDirectory = System.getProperty("user.dir");  
        String filePath = workingDirectory + "\\TestNG\\data\\" + dataFile;  
  
        try {  
            br = new BufferedReader(new FileReader(filePath));  
            while ((line = br.readLine()) != null) {  
                data = line.split(";");  
                if (notDataHeader) dataLines.add(data);  
                notDataHeader = true;  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return dataLines.iterator();  
    }

Как подсунуть DataProvider к тесту и так ясно:

@Test(description="Описание теста", dataProvider = "Data")  
    public void pay(String uin, String price) throws Exception {  
       dotest();  
    }

Это .csv файл с двумя значениями, подходящий к данному примеру. Если нужно добавить значений, не забываем добавить столько же входных параметров для функции public void pay:

uin;price  
12;990

Как заставить TestNG и ANT разговаривать по русски

Вчера мучался с этим полдня, обгуглился до дрожи в пальцах, но так и не нашел решение. TestNG при запуске через IDEA и своих отчетах выдавал мне ??? вместо русских букв. Самый фак был ещё и в том, что в testng.xml присутствовали параметры на русском языке и ничего не работало. Докопался до того, что при запуске сборки Ant она сама запускает JVM со своими параметрами, такими как classpath и ea (enable assertions), но как туда впихнуть -Dfile.encoding=UTF-8 ?

Оказывается, в таргете внутри ant.xml нужно всего лишь указать следующее (см. строку 4):

<target name="test" depends="compile">  
    <testng outputdir="${testdir}" classpathref="all.classpath" haltOnFailure="true">  
        <xmlfileset dir="${basedir}" includes="testng.xml"/>  
        <jvmarg value="-Dfile.encoding=UTF-8" />  
    </testng>  
</target>


Как в TestNG передавать переменные между файлами классов

Легко. Если у вас тестСьюты лежат не только в разных классах, но также и в разных .java файлах, нужные переменные можно передавать, записывая их в ITestContext в одном классе, а потом читая их оттудаже в другом классе. ITestContext это данные, которые могут перезаписывать или использовать любые тест методы в TestNG.

Записываем данные:

@Test(description="Найти код")  
public void check(ITestContext context) {  
    data = SomeClass.doSomething(driver, data, config);  
    context.setAttribute("myVariable", data);  
}

Читаем их в другом классе:

@Test(description="test2")  
public void test2(ITestContext context) {  
    String data = (String) context.getAttribute("myVariable");  
}