Data Driven Testing

Keywords: Python Pycharm NLP

The relationship between data-driven testing and automation:

  1. It's not about automated testing, it's about data-driven testing.
  2. On the premise of automated testing, data-driven testing is a way to optimize code.
    - The intent of automated testing is to maintain automated scripts.

Learning objectives:

  1. Common automated test patterns
  • Data Driven Testing
    - Test data determines test behavior and the final result. It is the basic form of testing and is commonly used.
  • Keyword Driven Testing
    - Highly encapsulated test code allows testers to automate tests directly through simple vocabulary function calls. For example, encapsulate the code of a login test into a login method that is called directly when it is used. Or, define the name used in the test to determine the behavior of the test.
  • Behavior Driven Testing
    - Highly encapsulated with natural language support, allows testers to automate testing through natural language descriptions, relies on frameworks, and is not widely available.
Feature:Search in Sogou website
   in order to Search inSougou website
   As a visitor
   We'll search the NBA best player
   # Scene: Search for a player in the NBA
   Scenario:Search NBA player
   	#The test code is as follows: Close to the natural language description, it has code at the bottom and cannot be changed at will
   	Given I have the English name "<search_name>"
   	When I search it in Sougou website
   	Then I see the entire name "<search_result>"
  1. Data Driven Testing Features
  • Reduce redundant code for easy code maintenance.
  • Centrally manage test data to facilitate test maintenance.
  • Easy to test framework extensions (modular programming thinking).
  1. Data Driven Test Implementation
  • Programming language: puthon3.x
  • Programming tool: pycharm
  • Third-party libraries used: requests, ddt, xlrd, xlutils

1. Environment

1. Install python

  • Notice adding environment variables

2. Install pycharm
3. Install third-party libraries

  • 3.1 Install ddt (data driver test)
    - A library for Python language data-driven testing.
  • 3.2 Install the requests Library
    - A library for automated interface testing.
  • 3.3 Install the xlrd Library
    - Library for reading excel files
  • 3.4 Install xlutils
    - A library that appends content to an existing excel file.

2. Create a project and write code

1. Create Project-Select Interpreter
The interpreter determines whether the downloaded plugin can be used

2. Write code

  • demo_Basic code.py
    - Defect: Cost-effective and time-consuming to maintain
import requests # Import interface automation library

# Address of interface
url = "http://172.31.191.129:8080/opencart/index.php?route=account/login"

# Entry, usually in a dictionary format
data = {
    "email":"admin@admin.com",
    "password":"123456"
}
# Send Request
re = requests.post(url=url,data=data)  

#print(re) # Print result: <Response [200]>, angle brackets indicate that this is an object, meaning more than 200, there is much more
#print(re.text) # View the text of the response.
result = "Logout Exit" in re.text   # Logout Exits as an Assertion
print(result)

# Password error
data = {
    "email":"admin@admin.com",
    "password":"12345"
}
re = requests.post(url=url,data=data)
result = "E-mail address/The phone number or password does not match." in re.text
print(result)   # Print result: True

# Account Error
data = {
    "email":"admin@admin.co",
    "password":"123456"
}
re = requests.post(url=url,data=data)
result = "E-mail address/The phone number or password does not match." in re.text
print(result)   # Print result: True

# Password is empty
data = {
    "email":"admin@admin.com",
    "password":""
}
re = requests.post(url=url,data=data)
result = "E-mail address/The phone number or password does not match." in re.text
print(result)   # Print result: True

# Account is empty
data = {
    "email":"",
    "password":"123456"
}
re = requests.post(url=url,data=data)
result = "E-mail address/The phone number or password does not match." in re.text
print(result)   # Print results: False_because this feature can also log in successfully when the account is empty and the password is correct, which is a bug

# Accounts, passwords are empty
data = {
    "email":"",
    "password":""
}
re = requests.post(url=url,data=data)
result = "E-mail address/The phone number or password does not match." in re.text
print(result)   # Print result: True
  • demo2_Simple Data Driven based on unittest framework.py
    - Defect: Not suitable for testing with large amounts of data, otherwise it's all data

pytest is more flexible and powerful than unittest

# Import test framework unit test
# Test framework, meaning exists: test code can be managed more easily.
import unittest
# Import content from ddt (data driver test) package
from ddt import ddt,data,unpack
import requests

# Add @ddt to indicate that the current test class is data-driven or otherwise data-driven
@ddt
# Step 1:
# Define a test class that inherits from the unittest.TestCase class
# Defined test class Demo name, is custom
class Demo(unittest.TestCase):
    # Step 4:
    # @data represents the test data that is currently required for this test case.
    # @data([first set of data], [second set of data], [third set of data], [fourth set of data], [fifth set of data]), participation and expected results form a set of data
    # There are several sets of test data behind @data, and its corresponding test cases will be iterated how many times to fetch new data each time.
    @data([{"email": "admin@admin.com","password": "123456"},"Logout Exit"],
          [{"email": "admin@admin.com","password": "12345"},"E-mail address/The phone number or password does not match."],
          [{"email": "admin@admin.co","password": "123456"},"E-mail address/The phone number or password does not match."],
          [{"email": "admin@admin.com","password": ""},"E-mail address/The phone number or password does not match."],
          [{"email": "","password": "123456"},"E-mail address/The phone number or password does not match."],
          [{"email": "","password": ""},"E-mail address/The phone number or password does not match."])
    # To be data driven, we define formal parameters for the test case, the number of parameters being the same as the number of elements in each set of test data.
    # When a test is executed, test data is automatically passed to the corresponding formal parameters

    # Step 6:
    # Split a set of data (list, tuple) into individual elements and pass them one-to-one to the formal parameters. Split only once.
    # In the absence of @unpack, in such cases, each set of list data contains both input parameters and expected results (multiple values), and without splitting the two, they are all passed to the first parameter, value, which is passed by default using a comma as the delivery standard. This is not required and errors are reported.
    @unpack #Step 2: Define the contents of the method by gluing this part of "demo_basic code.py"
    # The test case method in the unittest framework should start with test, followed by a custom name.
    def test_01_demo(self,value,pre_result):  # Step 5: Data transfer, method transfer, definition of formal parameters. The number of variables depends on the number of elements in each set of data, with two values, two parameters are defined
        url = "http://172.31.191.129:8080/opencart/index.php?route=account/login"
        # Step 3:
        # You need @data to have only one test case, but test data data is changing and expected results change. Delete the data here
        re = requests.post(url=url, data=value)  # Step 6: The variable value here, as data content, is assigned to data
        result = pre_result in re.text  # Step 6: Change the expected result here to the parameter pre_result
        print(result)
        # Print result: True True True True False True
        
if __name__=="__main__":
    unittest.main()
  • demo3_Save the data in a file.py
    Steps:
    1.Create a new.xls file locally (the new version does not support.xlsx and needs to be saved as.xls)
    2.Format a set of rows to prepare test data, such as:
  1. Write a file that reads excel, excel_utils.py
   # Step 2: Import the library xlrd reading excel
import xlrd
from xlutils import copy
import os

   # Step 1: Define a function get_excel_data
def get_excel_data():
   # Open excel file with xrld under specified path
   wb = xlrd.open_workbook("data.xls")
   # Select the appropriate label under excel (tell the computer to select the label in excel)
   sheet = wb.sheet_by_name("Sheet1")
   # Get the total number of rows of data in the current tab dynamically
   num = sheet.nrows # sheet.row_values() is to read the contents of a specified row, such as sheet.row_values(0), and to read the contents of the first row

   # Step 3: Loop through all the data in the current tab
   # Define an empty list to hold all test data.
   row_data = []  # Empty list to load new data
   for i in range(0,num):  # Sequence number: 0 to num
       # Gets the data for the specified line number
       data = sheet.row_values(i)
       # Converts a dictionary of type string to its own look (dictionary). Without conversion, each row of data is converted into a list, but the dictionary is quoted
       data[0] = eval(data[0])
       # Add each row of data to the list
       row_data.append(data)
   print(row_data)  # Print converted row_data
   # Print result: A binary list: [[first line], [second line], [third line], [fourth line], [fifth line]]
   return row_data


   # If the code doesn't want to be executed, you can put it under if u name_=="u main_u"
if __name__=="__main__":
   get_excel_data2()


4. Debug demo3_Save the data in a file.py

# Step 1: You can first copy the code from "demo2_Simple Data Driven.py based on unittest framework"

import unittest
from ddt import ddt,data,unpack
import requests
# Step 3:
# Import get_excel_data method (function) from written excel_utils.py
from excel_utils import get_excel_data

@ddt
class Demo(unittest.TestCase):
    # Step 6: Understand the following
    # get_excel_data() corresponds to the two-bit list [[first row], [second row], [third row], [fourth row], [fifth row]]
    # @unpack unpacks are equivalent to [first line], [second line], [third line], [fourth line], [fifth line], and cannot be used directly, referring to demo2_simple data-driven based unittest framework.py
    # So you need to unpack again
    # When *get_excel_data() calls a function, the function name is prefixed with *, indicating that the result is unpacked once.
    # Unpack twice with @unpack
    @data(*get_excel_data())  # Step 2: Data deletion in the data here changes to @data() because of excel data; Step 4: Pass excel data in
    @unpack
    def test_01_demo(self,value,pre_result):
        url = "http://172.31.191.129:8080/opencart/index.php?route=account/login"
        re = requests.post(url=url, data=value)
        result = pre_result in re.text
        print(result) # Print result: True True True True False True

if __name__=="__main__":
    unittest.main()


# This type also applies to form class tests in selenium, where different forms create different labels
  • demo4_Read all data from excel.py
    (More keyword driven)
    Steps:
    1.Create a new.xls file locally (the new version does not support.xlsx and needs to be saved as.xls)
    2.Format a set of rows, prepare test data, and customize column names as needed, such as:

    Like id, it is formatted as text to avoid displaying such numbers as.00 at runtime.
    The reason names are well defined in excel is to simplify the code so that test data is maintained directly in excel.
  1. Modify demo3 to form demo4_to read all data from excel.py
import unittest
from ddt import ddt,data,unpack
import requests
from excel_utils import get_excel_data2

@ddt
class Demo(unittest.TestCase):
    @data()
    @unpack
    def test_01_demo(self):
        re = requests.post(url=url, data=data)
        result = pre_result in re.text
        print(result)
if __name__=="__main__":
    unittest.main()
  1. Write a file that reads excel, excel_utils.py
# Step 2: Import the library xlrd reading excel
import xlrd
from xlutils import copy
import os

# Step 1: Define a function get_excel_data2
def get_excel_data2():
    wb = xlrd.open_workbook("data2.xls")
    sheet = wb.sheet_by_name("Sheet1")
    num = sheet.nrows
    row_data = []
    # Since the first row is the header content and is skipped, the data is taken from the second row, where the serial number starts from 1
    for i in range(1, num):
        data = sheet.row_values(i)
        data[4] = eval(data[4])
        row_data.append(data)
    print(row_data)
    return row_data

if __name__=="__main__":
    get_excel_data2()

5. Adjust final demo4_to read all data from excel.py

import unittest
from ddt import ddt,data,unpack
import requests
from excel_utils import get_excel_data2

@ddt
class Demo(unittest.TestCase):
    @data(*get_excel_data2()) # Step 1: Write data, parameters
    @unpack
    def test_01_demo(self,id,name,url,type,data,pre_result,result):  # Step 2: Pass-through. How many titles are in data2.excel, which must be consistent here. If only a portion is needed, you need to append a list to the get_excel_data2() function to define and generate a new list you want
        # Step 3: The original url here is unnecessary and can be deleted. Read it directly from the document data2.exl.
        re = requests.post(url=url, data=data)
        result = pre_result in re.text
        print(result)  # Run result True True True True False True
        
if __name__=="__main__":
    unittest.main()

In the example above, only post requests (re = requests.post(url=url, data=data)) are mentioned, if the data for the get request is also included?

  • demo5_Adaptive data test with Self-encapsulated request
    Steps:
    1.Create a new.xls file locally (the new version does not support.xlsx and needs to be saved as.xls)
    2.Format a set of rows, prepare test data, and customize column names as needed, such as:

    3. Get and post requests need to be encapsulated to be adaptive to get and post, request.py
# Step 1:
import requests

def send_request():
           requests.post()
           requests.get()
# Step 2:
import requests

def send_request(type):
    if type=="post":
           requests.post()
    elif type=="get":       
           requests.get()
# Step 3:
import requests

# You can't just pass in type s, but other values as well
def send_request(url,data,type):
    if type=="post":
    	   # A post request can pass two types of data
    	   requests.post(url=url,data=data)  # Sometimes passed data, add a column of data_type (data [dictionary] or json [string]) to excel
           requests.post(url=url,json=data)  # Sometimes passed json
    elif type=="get":       
           requests.get(url=url,params=data)
# Step 4:
import requests

def send_request(url,data,data_type,type):
    if type=="post":
        if data_type=="data":
            requests.post(url=url,data=data)
        elif data_type == "json":
            requests.post(url=url,json=data)
    elif type=="get":
        requests.get(url=url,params=data)
# Step 5:
# Sometimes requests may bring other messages, such as header s, cookies, etc. You can take **kwargs with you to represent receiving a dictionary
import requests

def send_request(url,data,data_type,type,**kwargs):
    if type=="post":
        if data_type=="data":
            requests.post(url=url,data=data,**kwargs)
        elif data_type == "json":
            requests.post(url=url,json=data,**kwargs)
    elif type=="get":
        requests.get(url=url,params=data,**kwargs)
# Step 6:
# Ultimately, you need to take out the response to the request, so you need to return the result, plus return
import requests

def send_request(url,data,data_type,type,**kwargs):
    if type=="post":
        if data_type=="data":
            return requests.post(url=url,data=data,**kwargs)
        elif data_type == "json":
            return requests.post(url=url,json=data,**kwargs)
    elif type=="get":
        return requests.get(url=url,params=data,**kwargs)

4. Write a file that reads excel, excel_utils.py

import unittest
from ddt import ddt,data,unpack
import requests
from excel_utils import get_excel_data2

def get_excel_data3():
    wb = xlrd.open_workbook("data3.xls")
    sheet = wb.sheet_by_name("Sheet1")
    num = sheet.nrows
    row_data = []
    # Since the first line is the heading content and is skipped, the serial number starts from 1
    for i in range(1, num):
        data = sheet.row_values(i)
        data[5] = eval(data[5])
        row_data.append(data)
    print(row_data)
    return row_data

5. Adjust final demo5_Adaptive data test with Self-encapsulated requests.py

Posted by shiggins on Sat, 11 Sep 2021 14:43:06 -0700