ผู้ให้บริการข้อมูลใน TestNG: Selenium ตัวอย่างการกำหนดพารามิเตอร์

⚡ สรุปอย่างชาญฉลาด

การกำหนดพารามิเตอร์ใน Selenium เรียกใช้เมธอดทดสอบเดียวซ้ำๆ กับชุดข้อมูลที่แตกต่างกัน เปลี่ยนสคริปต์เดียวให้เป็นการครอบคลุมการทดสอบที่ขับเคลื่อนด้วยข้อมูล TestNG มีกลไกสองอย่างสำหรับเรื่องนี้ ได้แก่ คำอธิบายประกอบ @Parameters ที่ทำงานร่วมกับ testng.xml และคำอธิบายประกอบ @DataProvider ที่ส่งคืนอาร์เรย์ของอ็อบเจ็กต์สองมิติ

  • 🎯 วัตถุประสงค์หลัก: การกำหนดค่าพารามิเตอร์ช่วยขจัดค่าคงที่ในสคริปต์ทดสอบ ทำให้ตรรกะเดียวกันสามารถตรวจสอบความถูกต้องของทุกชุดค่าผสมอินพุตที่แอปพลิเคชันต้องรองรับได้
  • 📄 กลไก XML: คำอธิบายประกอบ @Parameters อ่านคู่ชื่อ-ค่าที่ประกาศไว้ใน testng.xml ซึ่งเหมาะกับอินพุตแบบกำหนดค่าที่จำนวนชุดค่าผสมมีน้อย
  • 🏷️ ลำดับความสำคัญของขอบเขต: พารามิเตอร์ที่ประกาศในระดับการทดสอบจะแทนที่พารามิเตอร์ที่มีชื่อเดียวกันในระดับชุดทดสอบ ในขณะที่คลาสที่อยู่นอกการทดสอบนั้นจะยังคงอ่านค่าจากชุดทดสอบต่อไป
  • 🗂️ กลไกผู้ให้บริการข้อมูล: เมธอดที่ใส่คำอธิบายประกอบ @DataProvider จะส่งคืน Object[][] และ TestNG เรียกใช้การทดสอบหนึ่งครั้งต่อแถว โดยส่งแต่ละคอลัมน์เป็นอาร์กิวเมนต์
  • 🔗 ผู้ให้บริการภายนอก: การกำหนดให้ provider เป็นแบบ static และตั้งค่า dataProviderClass เป็น @Test จะทำให้คลาสทดสอบหลายคลาสสามารถใช้แหล่งข้อมูลเดียวกันได้
  • 🧭 ชุดข้อมูลแบบไดนามิก: การรับ Method หรือ ITestContext เป็นอาร์กิวเมนต์ของ provider จะส่งคืนข้อมูลที่แตกต่างกันไปตามแต่ละเมธอดทดสอบหรือตามกลุ่มที่รวมอยู่
  • 🛡️ ความล้มเหลวทั่วไป: ความไม่ตรงกันของชนิดข้อมูลระหว่างค่า XML และอาร์กิวเมนต์ของเมธอด รวมถึงพารามิเตอร์ที่ขาดหายไปซึ่งแก้ไขได้ด้วย @Optional เป็นสาเหตุหลักของข้อผิดพลาดในการเขียนคำอธิบายประกอบ

ผู้ให้บริการข้อมูลใน TestNG

ในการพัฒนาซอฟต์แวร์ เราต้องการให้มันทำงานได้อย่างถูกต้องกับชุดข้อมูลที่หลากหลายเสมอ เมื่อพูดถึงเรื่องนี้ การทดสอบ ซอฟต์แวร์นั้น การตรวจสอบชุดข้อมูลเพียงชุดเดียวไม่เพียงพอ เราจำเป็นต้องตรวจสอบว่าระบบยอมรับทุกชุดค่าผสมที่คาดหวังไว้หรือไม่ สำหรับเรื่องนั้น เราจำเป็นต้องกำหนดพารามิเตอร์ให้กับสคริปต์ทดสอบของเรา นี่คือจุดที่การกำหนดพารามิเตอร์เข้ามามีบทบาท

การกำหนดพารามิเตอร์ใน Selenium

การกำหนดพารามิเตอร์ใน Selenium เป็นกระบวนการในการกำหนดพารามิเตอร์ของสคริปต์ทดสอบเพื่อส่งข้อมูลหลายรายการไปยังแอปพลิเคชันขณะรันไทม์ เป็นกลยุทธ์ในการดำเนินการซึ่งจะรันกรณีทดสอบหลายครั้งโดยอัตโนมัติโดยใช้ค่าที่แตกต่างกัน แนวคิดที่ทำได้โดยการกำหนดพารามิเตอร์ของสคริปต์ทดสอบเรียกว่า การทดสอบที่ขับเคลื่อนด้วยข้อมูล.

ประเภทของการกำหนดพารามิเตอร์ใน TestNG

เพื่อให้เข้าใจเรื่องการกำหนดพารามิเตอร์ได้ชัดเจนยิ่งขึ้น เราจะมาดูตัวเลือกการกำหนดพารามิเตอร์ในเฟรมเวิร์กยอดนิยมตัวหนึ่งกัน Selenium เว็บไดรเวอร์ — TestNG.

มี สองทาง ซึ่งเราสามารถบรรลุถึงการกำหนดพารามิเตอร์ได้ TestNG:

  1. ด้วยความช่วยเหลือของ คำอธิบายพารามิเตอร์ และ TestNG XML ไฟล์

ประเภทของการกำหนดพารามิเตอร์ใน TestNG

  1. ด้วยความช่วยเหลือของ ผู้ให้บริการข้อมูล คำอธิบายประกอบ

ประเภทของการกำหนดพารามิเตอร์ใน TestNG

ประเภทของการกำหนดพารามิเตอร์ใน TestNG

แผนภาพด้านบนสรุปการแบ่งประเภทได้ดังนี้: พารามิเตอร์จาก testng.xml สามารถประกาศได้ที่ระดับชุดทดสอบหรือระดับการทดสอบ ในขณะที่พารามิเตอร์จาก DataProvider สามารถรับค่าได้ Method และ ITestContext ในฐานะที่เป็นข้อโต้แย้งของตัวเอง เรามาศึกษาข้อโต้แย้งเหล่านั้นอย่างละเอียดกันเถอะ

พารามิเตอร์ คำอธิบายประกอบใน TestNG

พารามิเตอร์ คำอธิบายประกอบใน TestNG @Parameters เป็นวิธีการที่ใช้ในการส่งค่าไปยังเมธอดทดสอบเป็นอาร์กิวเมนต์โดยใช้ไฟล์ .xml ผู้ใช้อาจต้องส่งค่าไปยังเมธอดทดสอบในระหว่างการทำงาน วิธีการใช้ @Parameters สามารถใช้ได้ในเมธอดใดๆ ที่มี @Test, @Before, @After หรือ @Factory อยู่แล้ว

คำอธิบายพารามิเตอร์ด้วย Testng.xml

เลือกใช้การกำหนดพารามิเตอร์โดยใช้คำอธิบายประกอบเมื่อคุณไม่ต้องการจัดการกับความซับซ้อน และจำนวนชุดค่าผสมของอินพุตมีน้อย

มาดูกันว่ามันทำงานอย่างไร

สถานการณ์ทดสอบ

ขั้นตอน 1) เปิดเบราว์เซอร์แล้วไปที่ Googleด้วย.

ขั้นตอน 2) ป้อนคำค้นหา

การใส่คำอธิบายพารามิเตอร์ด้วย Testng.Xml

ขั้นตอน 3) ตรวจสอบว่าค่าที่ป้อนตรงกับค่าที่ได้จากข้อมูลทดสอบของเรา

ขั้นตอน 4) ทำซ้ำขั้นตอนที่ 2 และ 3 จนกว่าจะป้อนค่าทั้งหมดเสร็จ

ผู้เขียนทดสอบ ค้นหาคีย์
Guru99 อินเดีย
Krishna สหรัฐอเมริกา
ภุพเพช สาธารณรัฐประชาชนจีน

นี่คือตัวอย่างวิธีการทำ ไม่มี พารามิเตอร์:

package parameters;

import org.testng.annotations.Test;
import org.testng.AssertJUnit;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class NoParameterWithTestNGXML {
    WebDriver driver;

    @Test
    public void testNoParameter() throws InterruptedException {
        String author = "guru99";
        String searchKey = "india";

        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

        driver.get("https://google.com");
        WebElement searchText = driver.findElement(By.name("q"));
        // Searching text in the Google text box
        searchText.sendKeys(searchKey);

        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = " + searchText.getDomProperty("value")
                + " ::: Value given by input = " + searchKey);
        // Verifying the value in the Google search box
        AssertJUnit.assertTrue(searchText.getDomProperty("value").equalsIgnoreCase(searchKey));
    }
}

⚠️ Selenium หมายเหตุปี 4: สามบรรทัดในเวอร์ชันดั้งเดิมของตัวอย่างนี้ไม่สามารถคอมไพล์ได้อีกต่อไป หรือถูกยกเลิกการใช้งานในเวอร์ชันปัจจุบัน Selenium เผยแพร่ System.setProperty("webdriver.gecko.driver", …) ไม่จำเป็นจาก Selenium 4.6 เป็นต้นไปเพราะ Selenium ตัวจัดการจะแก้ไขไฟล์ไบนารีของไดรเวอร์โดยอัตโนมัติ implicitlyWait(10, TimeUnit.SECONDS) ได้ทำการแก้ไขปัญหาการโอเวอร์โหลดแล้ว Selenium 4 และถูกแทนที่ด้วย implicitlyWait(Duration.ofSeconds(10)). getAttribute() ถูกยกเลิกการใช้งานใน Selenium 4.27 ดังนั้นการอ่านกล่องข้อความจึงใช้ getDomProperty("value")ตัวอย่างทั้งหมดด้านล่างนี้ใช้การแก้ไขสามประการเดียวกัน

ศึกษาตัวอย่างข้างต้นและลองนึกภาพว่าโค้ดจะซับซ้อนแค่ไหนเมื่อทำซ้ำแบบนี้สำหรับชุดข้อมูลป้อนเข้าสามแบบ

ต่อไปเรามาทำการกำหนดค่าพารามิเตอร์โดยใช้ TestNGในการทำเช่นนั้น คุณต้องทำดังนี้:

  • สร้างไฟล์ XML ซึ่งจะเก็บพารามิเตอร์
  • ในการทดสอบ ให้เพิ่มคำอธิบายประกอบ @Parameters

การใส่คำอธิบายพารามิเตอร์ด้วย Testng.Xml

นี่คือโค้ดฉบับสมบูรณ์

ระดับการทดสอบ TestNG. Xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="TestSuite" thread-count="3">
  <parameter name="author" value="Guru99" />
  <parameter name="searchKey" value="India" />
  <test name="testGuru">
    <parameter name="searchKey" value="UK" />
    <classes>
      <class name="parameters.ParameterWithTestNGXML"></class>
    </classes>
  </test>
</suite>

พารามิเตอร์ด้วยTestNGไฟล์ XML.java

package parameters;

import org.testng.AssertJUnit;
import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class ParameterWithTestNGXML {
    WebDriver driver;

    @Test
    @Parameters({"author", "searchKey"})
    public void testParameterWithXML(@Optional("Abc") String author, String searchKey)
            throws InterruptedException {

        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");

        WebElement searchText = driver.findElement(By.name("q"));
        // Searching text in the Google text box
        searchText.sendKeys(searchKey);

        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = " + searchText.getDomProperty("value")
                + " ::: Value given by input = " + searchKey);
        // Verifying the value in the Google search box
        AssertJUnit.assertTrue(searchText.getDomProperty("value").equalsIgnoreCase(searchKey));
    }
}

ในการเรียกใช้สคริปต์ ให้เลือกไฟล์ XML แล้วเรียกใช้ในฐานะไฟล์ XML TestNG บน

คลิกขวาที่ไฟล์ .xml -> เรียกใช้ในฐานะ -> TestNG ห้องสวีท (หมายเหตุ: ห้องสวีท)

พารามิเตอร์ด้วยTestNGไฟล์ XML.java

สามารถกำหนดพารามิเตอร์ได้สองระดับ:

  1. ห้องสวีท — พารามิเตอร์ภายใน <suite> แท็กของ TestNG ไฟล์ XML คือพารามิเตอร์ระดับชุดโปรแกรม
  2. ระดับการทดสอบ — พารามิเตอร์ภายใน <test> แท็กของ TestNG ไฟล์ XML คือพารามิเตอร์ระดับการทดสอบ

ต่อไปนี้คือการทดสอบแบบเดียวกันโดยใช้พารามิเตอร์ระดับชุดทดสอบ:

พารามิเตอร์ด้วยTestNGไฟล์ XML.java

หมายเหตุ: หากชื่อพารามิเตอร์เหมือนกันทั้งในระดับชุดทดสอบและระดับการทดสอบ พารามิเตอร์ในระดับการทดสอบจะมีลำดับความสำคัญเหนือกว่าพารามิเตอร์ในระดับชุดทดสอบ ในกรณีนั้น คลาสทั้งหมดที่อยู่ภายในระดับการทดสอบนั้นจะใช้พารามิเตอร์ที่ถูกแทนที่ร่วมกัน ในขณะที่คลาสที่อยู่นอกระดับการทดสอบนั้นจะยังคงใช้พารามิเตอร์ในระดับชุดทดสอบต่อไป

พารามิเตอร์ด้วยTestNGไฟล์ XML.java

การแก้ไขปัญหา

ฉบับที่ 1: หากค่าพารามิเตอร์ในไฟล์ testng.xml ไม่สามารถแปลงประเภทให้ตรงกับพารามิเตอร์ของเมธอดทดสอบที่เกี่ยวข้องได้ จะทำให้เกิดข้อผิดพลาด

พิจารณาตัวอย่างต่อไปนี้:

การแก้ไขปัญหา

ในที่นี้ คุณลักษณะ 'ผู้เขียน' เท่ากับ 'Guruค่า '99' เป็นสตริง ในขณะที่เมธอดทดสอบที่เกี่ยวข้องคาดหวังค่าจำนวนเต็ม ดังนั้นจึงเกิดข้อผิดพลาดขึ้น

ฉบับที่ 2: ค่า @Parameters ของคุณไม่มีค่าที่ตรงกันในไฟล์ testng.xml

คุณสามารถแก้ไขปัญหานี้ได้โดยการเพิ่ม @คำอธิบายประกอบเพิ่มเติม (ไม่จำเป็น) ไปยังพารามิเตอร์ที่เกี่ยวข้องในวิธีการทดสอบ

การแก้ไขปัญหา

ฉบับที่ 3: คุณต้องการทดสอบค่าหลายค่าของพารามิเตอร์เดียวกันโดยใช้ไฟล์ testng.xml

คำตอบง่ายๆ คือ ทำแบบนั้นไม่ได้ คุณสามารถมีพารามิเตอร์ได้หลายตัว แต่แต่ละพารามิเตอร์สามารถเก็บค่าได้เพียงค่าเดียวเท่านั้น วิธีนี้จะป้องกันการกำหนดค่าตายตัวลงในสคริปต์และทำให้โค้ดสามารถนำกลับมาใช้ใหม่ได้ — คิดว่ามันเป็นเหมือนไฟล์การตั้งค่าสำหรับสคริปต์ของคุณ หากคุณต้องการค่าหลายค่าสำหรับพารามิเตอร์ตัวเดียว ให้ใช้ DataProvider แทน

ผู้ให้บริการข้อมูลใน TestNG

ผู้ให้บริการข้อมูลใน TestNG เป็นวิธีการที่ใช้เมื่อผู้ใช้จำเป็นต้องส่งพารามิเตอร์ที่ซับซ้อน พารามิเตอร์ที่ซับซ้อนจำเป็นต้องสร้างขึ้นจาก Java — สามารถส่งผ่านอ็อบเจ็กต์ที่ซับซ้อน อ็อบเจ็กต์จากไฟล์คุณสมบัติ หรืออ็อบเจ็กต์จากฐานข้อมูลได้โดยใช้เมธอดตัวให้บริการข้อมูล เมธอดนี้จะมีคำอธิบายประกอบด้วย @DataProvider และจะส่งคืนอาร์เรย์ของอ็อบเจ็กต์

พารามิเตอร์ที่ใช้ Dataprovider

การใช้ annotation @Parameters นั้นง่าย แต่หากต้องการทดสอบด้วยชุดข้อมูลหลายชุด เราจำเป็นต้องใช้ Data Provider

ในการกรอกแบบฟอร์มออนไลน์หลายพันรายการโดยใช้เฟรมเวิร์กการทดสอบของเรา เราต้องการวิธีการที่แตกต่างออกไป ซึ่งสามารถรองรับชุดข้อมูลขนาดใหญ่มากในขั้นตอนการทำงานเดียว

แนวคิดที่ขับเคลื่อนด้วยข้อมูลนี้บรรลุผลได้โดย @DataProvider คำอธิบายประกอบใน TestNG.

พารามิเตอร์ที่ใช้ Dataprovider

มันมีเพียงหนึ่งเดียว คุณลักษณะ 'ชื่อ'หากคุณไม่ได้ระบุแอตทริบิวต์ name ชื่อของ DataProvider จะเหมือนกับชื่อของเมธอดที่เกี่ยวข้อง

ผู้ให้บริการข้อมูลส่งคืนข้อมูล สองมิติ Java วัตถุ ไปยังเมธอดทดสอบ และเมธอดทดสอบจะถูกเรียกใช้ M ครั้งสำหรับอาร์เรย์ของอ็อบเจ็กต์ขนาด M×N ตัวอย่างเช่น หาก DataProvider ส่งคืนอาร์เรย์ของอ็อบเจ็กต์ขนาด 2×3 กรณีทดสอบที่เกี่ยวข้องจะถูกเรียกใช้ 2 ครั้ง โดยแต่ละครั้งมีพารามิเตอร์ 3 ตัว

พารามิเตอร์ที่ใช้ Dataprovider

ตัวอย่างที่สมบูรณ์

พารามิเตอร์ที่ใช้ Dataprovider

package parameters;

import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

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

public class ParameterByDataprovider {
    WebDriver driver;

    @BeforeTest
    public void setup() {
        // Create the Firefox driver object
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    /** Test case to verify the Google search box */
    @Test(dataProvider = "SearchProvider")
    public void testMethod(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        // Search value in the Google search box
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        // Verify if the value in the Google search box is correct
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /**
     * @return Object[][] where the first column contains 'author'
     * and the second column contains 'searchKey'
     */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider() {
        return new Object[][] {
            { "Guru99", "India" },
            { "Krishna", "UK" },
            { "Bhupesh", "USA" }
        };
    }
}

เรียกใช้ DataProvider จากคลาสอื่น

โดยปกติแล้ว DataProvider จะอยู่ในคลาสเดียวกับเมธอดทดสอบ หรือในคลาสพื้นฐานของเมธอดนั้น หากต้องการย้ายไปอยู่ในคลาสอื่น ให้สร้างเมธอด DataProvider ขึ้นมาใหม่ คงที่ และเพิ่มแอตทริบิวต์ dataProviderClass ไป @ทดสอบ คำอธิบายประกอบ

เรียกใช้ DataProvider จากคลาสที่ต่างกัน

Code ตัวอย่าง

เรียกใช้ DataProvider จากคลาสที่ต่างกัน

TestClass parameterDataproviderWithClassLevel.java

package parameters;

import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ParameterDataproviderWithClassLevel {
    WebDriver driver;

    @BeforeTest
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider", dataProviderClass = DataproviderClass.class)
    public void testMethod(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        // Search text in the Google text box
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        // Get text from the search box
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        // Verify if the search box has the correct value
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }
}

DataproviderClass.java

package parameters;

import org.testng.annotations.DataProvider;

public class DataproviderClass {

    @DataProvider(name = "SearchProvider")
    public static Object[][] getDataFromDataprovider() {
        return new Object[][] {
            { "Guru99", "India" },
            { "Krishna", "UK" },
            { "Bhupesh", "USA" }
        };
    }
}

ประเภทของพารามิเตอร์ใน Dataprovider

เมธอด DataProvider รองรับพารามิเตอร์สองประเภท

วิธี — ถ้าหาก เดียวกัน DataProvider ควรทำงานแตกต่างกันไปตามวิธีการทดสอบแต่ละแบบ โปรดใช้พารามิเตอร์ Method

ประเภทของพารามิเตอร์ใน Dataprovider

ในตัวอย่างต่อไปนี้:

  • เราตรวจสอบว่าชื่อเมธอดคือ testMethodA หรือไม่
  • ถ้าใช่ ให้ส่งคืนชุดค่าหนึ่งชุด
  • มิเช่นนั้น ให้ส่งค่าชุดอื่นกลับมา
package parameters;

import java.lang.reflect.Method;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByMethodInDataprovider {

    WebDriver driver;

    @BeforeTest
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider")
    public void testMethodA(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        // Print author and search string
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    @Test(dataProvider = "SearchProvider")
    public void testMethodB(String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        // Print only the search string
        System.out.println("Welcome ->Unknown user Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /** The DataProvider returns values based on the test method name */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider(Method m) {
        if (m.getName().equalsIgnoreCase("testMethodA")) {
            return new Object[][] {
                { "Guru99", "India" },
                { "Krishna", "UK" },
                { "Bhupesh", "USA" }
            };
        } else {
            return new Object[][] {
                { "Canada" },
                { "Russia" },
                { "Japan" }
            };
        }
    }
}

นี่คือผลลัพธ์:

ประเภทของพารามิเตอร์ใน Dataprovider

ITestContext — สามารถนำมาใช้สร้างพารามิเตอร์ที่แตกต่างกันสำหรับกรณีทดสอบโดยอิงตามกลุ่มได้

ในชีวิตจริง คุณสามารถใช้ ITestContext เพื่อปรับเปลี่ยนค่าพารามิเตอร์ตามวิธีการทดสอบ โฮสต์ หรือการกำหนดค่าการทดสอบได้

ประเภทของพารามิเตอร์ใน Dataprovider

ในตัวอย่างโค้ดต่อไปนี้:

  • เรามี 2 กลุ่ม คือ กลุ่ม A และกลุ่ม B
  • วิธีการทดสอบแต่ละวิธีถูกกำหนดให้กับกลุ่ม
  • ถ้าค่ากลุ่มเป็น A จะส่งคืนชุดข้อมูลหนึ่งชุด
  • ถ้าค่ากลุ่มเป็น B ระบบจะส่งคืนชุดข้อมูลอื่น
package parameters;

import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByITestContextInDataprovider {
    WebDriver driver;

    @BeforeTest(groups = {"A", "B"})
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider", groups = "A")
    public void testMethodA(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    @Test(dataProvider = "SearchProvider", groups = "B")
    public void testMethodB(String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->Unknown user Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /** The DataProvider supplies an Object array based on ITestContext */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider(ITestContext c) {
        Object[][] groupArray = null;
        for (String group : c.getIncludedGroups()) {
            if (group.equalsIgnoreCase("A")) {
                groupArray = new Object[][] {
                    { "Guru99", "India" },
                    { "Krishna", "UK" },
                    { "Bhupesh", "USA" }
                };
                break;
            } else if (group.equalsIgnoreCase("B")) {
                groupArray = new Object[][] {
                    { "Canada" },
                    { "Russia" },
                    { "Japan" }
                };
                break;
            }
        }
        return groupArray;
    }
}

หมายเหตุ ถ้าคุณรัน TestNG หากเรียกใช้คลาสโดยตรง ระบบจะเรียกใช้ตัวให้บริการข้อมูลก่อน และตัวให้บริการจะไม่สามารถอ่านข้อมูลกลุ่มได้เนื่องจากกลุ่มยังไม่พร้อมใช้งาน การเรียกใช้คลาสผ่าน testng.xml จะทำให้ข้อมูลกลุ่มพร้อมใช้งานผ่าน ITestContext ใช้ XML ต่อไปนี้เพื่อเรียกใช้การทดสอบ:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="test-parameter">

  <test name="example1">
    <groups>
      <run>
        <include name="A" />
      </run>
    </groups>
    <classes>
      <class name="parameters.ParameterByITestContextInDataprovider" />
    </classes>
  </test>

  <test name="example2">
    <groups>
      <run>
        <include name="B" />
      </run>
    </groups>
    <classes>
      <class name="parameters.ParameterByITestContextInDataprovider" />
    </classes>
  </test>

</suite>

ตอนนี้เราได้อธิบายกลไกทั้งสองแบบแล้ว ดังนั้นคำถามในทางปฏิบัติก็คือควรเลือกใช้กลไกใด

@Parameters กับ @DataProvider: ควรใช้อันไหนดี

ทั้งสองแนวทางไม่สามารถใช้แทนกันได้ การตัดสินใจขึ้นอยู่กับว่าการทดสอบต้องการค่าผสมกี่แบบ และค่าเหล่านั้นมาจากแหล่งใด

เกณฑ์ @พารามิเตอร์ + testng.xml @DataProvider
ค่าต่อพารามิเตอร์ หนึ่งอันพอดี แถวไม่จำกัดจำนวน
แหล่งข้อมูล ข้อความคงที่ในไฟล์ XML Java โค้ด, Excel, CSV, ฐานข้อมูล, API
ประเภทที่รองรับ การแปลงประเภทค่าจากสตริง ใด Java วัตถุ
การเรียกใช้การทดสอบ ครั้งละหนึ่งครั้งต่อการกำหนดค่า ครั้งละหนึ่งแถวข้อมูล
การเปลี่ยนแปลงข้อมูลจำเป็นต้อง การแก้ไขไฟล์ XML การแก้ไขซอร์สโค้ด มักไม่จำเป็นต้องคอมไพล์ใหม่
เหมาะที่สุดสำหรับ ค่าสภาพแวดล้อมและการตั้งค่าต่างๆ เช่น เบราว์เซอร์ URLข้อมูลประจำตัว การทดสอบโดยใช้ข้อมูลเป็นหลัก ครอบคลุมการผสมผสานข้อมูลป้อนเข้าหลายรูปแบบ

ในทางปฏิบัติ ชุดโปรแกรมส่วนใหญ่ใช้ทั้งสองอย่าง: @Parameters ทำหน้าที่เก็บค่าการตั้งค่าสภาพแวดล้อมซึ่งคงที่ตลอดการทำงาน และ @DataProvider ทำหน้าที่จัดหาข้อมูลทางธุรกิจที่เปลี่ยนแปลงไป เมื่อชุดข้อมูลมีขนาดใหญ่เกินกว่าอาร์เรย์ที่กำหนดไว้ตายตัว ขั้นตอนต่อไปคือการอ่านข้อมูลจากสเปรดชีต

วิธีการอ่านข้อมูลทดสอบจากไฟล์ Excel โดยใช้ DataProvider

อาร์เรย์ที่กำหนดค่าตายตัวจะหยุดปรับขนาดเมื่อผู้ทดสอบที่ไม่ได้เขียนโค้ด Java จำเป็นต้องรักษาข้อมูลไว้ การย้ายแถวลงในสเปรดชีตจะแยกข้อมูลทดสอบออกจากตรรกะการทดสอบ ซึ่งเป็นรูปแบบที่ใช้งานได้จริงของ การทดสอบที่ขับเคลื่อนด้วยข้อมูลApache POI อ่านเวิร์กบุ๊ก และ DataProvider จะแปลงแต่ละแถวให้เป็นการเรียกใช้งานทดสอบหนึ่งครั้ง

  1. เพิ่มการพึ่งพา (dependency) เพิ่ม org.apache.poi:poi-ooxml ใน Maven ของคุณ หรือ Gradle สร้าง. ooxml artifact รองรับรูปแบบไฟล์ .xlsx; แบบธรรมดา poi รองรับเฉพาะไฟล์ .xls รุ่นเก่าเท่านั้น
  2. สร้างเวิร์กบุ๊ก วางแถวส่วนหัวไว้ในแถวที่ 0 และวางกรณีทดสอบหนึ่งกรณีต่อแถวถัดจากนั้น โดยแต่ละคอลัมน์จะแทนอาร์กิวเมนต์ของวิธีการทดสอบหนึ่งข้อ
  3. อ่านข้อมูลจากชีตลงในอาร์เรย์ กำหนดขนาดของอ็อบเจ็กต์[][] จากจำนวนแถวและเซลล์ เพื่อให้สามารถดึงแถวใหม่ได้โดยไม่ต้องแก้ไขโค้ด
  4. ส่งคืนจากผู้ให้บริการ ลายเซ็นของเมธอดทดสอบยังคงเหมือนเดิมทุกประการ
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.testng.annotations.DataProvider;

public class ExcelDataProvider {

    @DataProvider(name = "SearchProvider")
    public Object[][] readSearchData() throws Exception {
        FileInputStream file = new FileInputStream("src/test/resources/testdata.xlsx");
        Workbook workbook = new XSSFWorkbook(file);
        Sheet sheet = workbook.getSheetAt(0);

        // Skip the header row, so subtract one from the physical row count
        int rows = sheet.getLastRowNum();
        int cols = sheet.getRow(0).getPhysicalNumberOfCells();
        Object[][] data = new Object[rows][cols];

        for (int i = 1; i <= rows; i++) {
            for (int j = 0; j < cols; j++) {
                data[i - 1][j] = sheet.getRow(i).getCell(j).getStringCellValue();
            }
        }
        workbook.close();
        file.close();
        return data;
    }
}

💡 เคล็ดลับ: โทร getStringCellValue() เฉพาะในเซลล์ที่จัดรูปแบบเป็นข้อความเท่านั้น เซลล์ตัวเลขจะเกิดข้อผิดพลาด IllegalStateExceptionซึ่งเป็นข้อผิดพลาดที่พบบ่อยที่สุดเมื่อสเปรดชีตมีรหัสหรือจำนวนเงิน ใช้ DataFormatter เพื่ออ่านเซลล์ทุกประเภทเป็นสตริง หรือเปิดใช้งาน cell.getCellType() และแปลงอย่างชัดเจน

เมื่อข้อมูลถูกแยกออกมาภายนอก การเพิ่มกรณีทดสอบอีกร้อยกรณีก็กลายเป็นเพียงการแก้ไขสเปรดชีตแทนที่จะเป็นการแก้ไขโค้ด และผู้ให้บริการรายเดียวกันสามารถป้อนคลาสทดสอบหลายคลาสผ่านทางระบบได้ dataProviderClass คุณลักษณะที่แสดงไว้ก่อนหน้านี้

คำถามที่พบบ่อย

ใช่ การตั้งค่า @DataProvider(name="x", parallel=true) รันแถวต่างๆ พร้อมกัน แต่ละเธรดต้องการอินสแตนซ์ WebDriver ของตัวเอง ดังนั้นให้เก็บไดรเวอร์ไว้ใน ThreadLocal มิฉะนั้นการทดสอบจะรบกวนซึ่งกันและกัน

ใช่. TestNG ยอมรับ Iterator<Object[]>ซึ่งจะส่งข้อมูลแถวแบบค่อยเป็นค่อยไปแทนที่จะสร้างอาร์เรย์ทั้งหมดลงในหน่วยความจำ วิธีนี้เหมาะสำหรับชุดข้อมูลขนาดใหญ่มากหรือแถวที่ส่งมาจากเคอร์เซอร์ฐานข้อมูล

ใช่. AI เครื่องมือเหล่านี้สร้างค่าขอบเขต ข้อมูลป้อนเข้าที่ไม่ถูกต้อง และบันทึกสังเคราะห์ที่สมจริงจากข้อกำหนดภาคสนาม Revตรวจสอบผลลัพธ์เพื่อหาข้อมูลซ้ำ และยืนยันว่าผลลัพธ์ที่คาดหวังถูกต้องก่อนที่จะเพิ่มแถวลงในฐานข้อมูล

ผู้ช่วย AI จะระบุแถวข้อมูลที่ซ้ำซ้อนซึ่งใช้เส้นทางการทำงานของโค้ดเดียวกัน จัดกลุ่มความล้มเหลวตามลักษณะการป้อนข้อมูลที่ใช้ร่วมกัน และแนะนำวิธีการแก้ไขด้วยตนเอง ตัวระบุตำแหน่ง เมื่อมีการเปลี่ยนแปลงมาร์กอัปแอปพลิเคชัน

ค่าต่างๆ ในไฟล์ testng.xml จะถูกอ่านเป็นข้อความเสมอ TestNG แปลงค่าเหล่านั้นให้เป็นประเภทอาร์กิวเมนต์ที่ประกาศไว้ ดังนั้นค่าที่ไม่ใช่ตัวเลขที่ผูกกับอาร์กิวเมนต์ประเภท int จะใช้งานไม่ได้ ให้จับคู่ค่า XML กับลายเซ็นของเมธอด หรือรับค่าสตริงแล้วแยกวิเคราะห์

สรุปโพสต์นี้ด้วย: