前書き
このように感じたことはありますか?自動テストのプロセスでは、API自動テストであろうとUI自動テストであろうと、テストスクリプトを作成する時間の大部分は、データの準備(setUp)とデータのクリーンアップ(tearDown)です。データは自動テストの重要な部分だからです。このように、データ駆動型は非常に重要です。次に共有するコンテンツは次のとおりです。DDT、Unittestテストフレームワークで一般的に使用されるデータ駆動型フレームワーク。
データ駆動型
1.データ駆動型とは何ですか?
データ駆動型とは、自動テストでテストデータを処理する方法を指します。
通常、テストデータは関数関数から分離され、関数関数の外部の場所に保存されます。自動テストの実行中、データ駆動型フレームワークはデータソース内のデータを読み取り、そのデータをパラメーターとして関数関数に渡し、データの数に応じて同じ関数関数を複数回実行します。
データ駆動型データソースは、関数、CSVファイル、Excelテーブル、TXTファイル、およびデータベース以外のデータコレクションです。
2.データ駆動型の利点は何ですか?
(1)繰り返しコードの削減
次の例を通して、データ駆動型がどのように繰り返しコードを削減できるかを見てみましょう。
def test_001(user, pwd, num):
# 实际函数逻辑
pass
# 如果没有数据驱动,你的代码可能会是这样的:
test_001('one', 'test_one', 1)
test_001('two', 'test_two', 2)
test_001('three', 'test_three', 3)
データドリブンを使用せず、同じ関数関数に対して複数のテストデータがある場合、この関数関数を複数回呼び出すことしかできません。さらに、特定のテストデータを変更/削除したら、対応する関数を変更する必要があります。関数呼び出しでのテストデータは非常に不便です。
テスト駆動を使用する場合、コードは次のようになります。
# origin_data指向一个文件,这个文件里存储有你所有的测试数据。
origin_data = './tests/data/testdata.csv'
# dataDrivenDecorator是你实现数据驱动的装饰器
@dataDrivenDecorator(origin_data)
def test_001(user, pwd, num):
# 实际函数逻辑
pass
この場合、複数の呼び出しを行う必要はなく、テストデータが変更された場合は、データソースファイルのデータを変更するだけで済みます。
(2)データが属するテストケースの障害は、他のテストデータに対応するテストケースに影響を与えません。
次の例を通して、他のテストデータに対応するテストケースがどのように影響を受けないかを見てみましょう。
データ駆動型を使用しない場合は、次のいずれかの関数があると想定します。
test_data = [0, 1, 0, 1]
def test_001(data):
for x in data:
assert x > 0
test_001(test_data)
実行結果は下図のようになります。
実行結果から、test_dataの最初の値は0であるため、0以下であることがわかります。したがって、アサーションは失敗し、test_dataテストデータセットの0以降のすべてのテストデータは実行されません。
データドライブがある場合、データドライブはこのテストをテストデータに従って複数のテストに分解するため、最初のテストデータが失敗しても、後続のテスト結果に影響はありません。
3. Pythonで広く使用されているデータ駆動型フレームワークは何ですか?
-
DDT(Data-Driven Tests)、通常はUnittestと組み合わせます
-
パラメータ化された、データ駆動型を実装するためにPytestで一般的に使用されるフレームワーク
DDTに含まれるデコレータ
1クラスのデコレータ
ddtクラスデコレータはTestCaseのサブクラスでデコレートする必要があります。TestCaseはUnittestフレームワークの基本クラスであり、テスト操作を駆動するためにTestRunnerが必要とするインターフェイスを実装します。
2つのメソッドデコレータ
それらは、dataとfile_dataです。
データデコレータはテストデータを直接提供します
。file_dataデコレータはJSONまたはYAMLファイルからテストデータをロードします。
DDTを使用する手順は次のとおりです。
-
@ddtを使用して、テストクラスを装飾します。
-
@dataまたは@file_dataを使用して、データ駆動型で必要なテストメソッドを装飾します。
-
テストデータのセットに複数のパラメーターがある場合は、解凍する必要があります。@ unpackを使用してテストメソッドを装飾します。
PythonインストールDDT:
インストールコマンド:pip installddtまたはpython-m pip install ddt
DDTの使用
(1)、ddtはデータを直接提供します
from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
# ddt一定是装饰在TestCase的子类上
@ddt
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
# data表示测试数据是直接提供的。
# unpack表示,对于每一组数据,如果它的值是list或者tuple,那么就分拆成独立的参数。
@data(['Testing', 'Testing'], ['hello_world.com','Testing'])
@unpack
def test_baidu_search(self, search_string, expect_string):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").send_keys(search_string)
driver.find_element_by_id("su").click()
time.sleep(2)
search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
print(search_results)
self.assertEqual(expect_string in search_results, True)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main(verbosity=2)
この例では、@ dataデコレータを直接使用しました。このデコレータでは、テスト用に2セットのデータ、つまり['Testing'、 'Testing']と['hello_world.com'、 'Testing']を提供します。次に、@ unpackデコレータを使用してそれぞれのデータを配置します。データはパラメーターとして解凍され、関数test_baidu_searchに渡されます。
上記のコードを実行すると、結果から、テストケースtest_baidu_searchは1つしかないことがわかります。しかし、生成されたテストレポートでは、「XXで2つのテストを実行」が表示されます。つまり、test_baidu_searchが2回実行されました。これは、DDTが機能していることです。
これは、各グループに複数のパラメータセットと複数のデータがある場合です。各グループにデータが1つしかない場合はどうなりますか?以下を変更するだけです。
# 如仅有一个参数,那么直接在data里写参数就好。
# 仅有一个参数的情况下,无须再用@unpack装饰测试方法。
@data('data1', 'data2')
(2)、ddtは関数を使用してデータを提供します
ddtはデータを直接提供します。ただし、上記の@data()のパラメーターにデータを直接書き込む場合を除き、別の状況があります。つまり、データは最初にデータを取得します。関数、そしてパラメータで@data()に書き込まれます。
from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
def get_test_data():
# 这里写你获取测试数据的业务逻辑。
# 获取到后,把数据返回即可。
# 注意,如果多组数据,需要返回类似([数据1-参数1, 数据1-参数2],[数据2-参数1, 数据2-参数2])这样的格式,方便ddt.data()解析
# 解析后返回的数据格式如下:
results = (['Testing', 'Testing'], ['hello_world.com', 'Testing'])
return results
# ddt一定是装饰在TestCase的子类上
@ddt
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
# data表示data是直接提供的。注意data里的参数我写了函数get_test_data()的返回值,并且以*为前缀,代表返回的是可变参数。
# unpack表示,对于每一组数据,如果它的值是list或者tuple,那么就分拆成独立的参数。
@data(*get_test_data())
@unpack
def test_baidu_search(self, search_string, expect_string):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").send_keys(search_string)
driver.find_element_by_id("su").click()
time.sleep(2)
search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
print(search_results)
self.assertEqual(expect_string in search_results, True)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main(verbosity=2)
上記の例では、テストデータを取得するための関数get_test_data()を作成しました。この関数は、ビジネスロジックに応じて、パラメーターを受け取ることも、パラメーターを受け取らないこともできます。
注:get_test_data()の戻り値は、ddt.data()の許容可能なデータ形式に準拠している必要があります。
つまり、データのセット、各データは単一の値、複数のデータのセット、データの各グループはリストまたは辞書です。
(3)ddtはファイルを使用してデータを提供します:
@ddtを使用してJSONおよびYAMLのデータを直接提供することに加えて、DDTはファイルを介したデータのロードもサポートします。
ただし、デフォルトではYAMLとJSONの2つの形式のみがサポートされており、「。yml」または「.yaml」で終わる形式のみがYAMLファイルと見なされ、その他の形式はJSONファイルと見なされます。
上記のユースケースをJSONファイルを使用するように変更すると、ユースケースは次のようになり
ます。
まず、test_baidu.pyと同じ名前のファイルtest_baidu.jsonを作成します。内容は次のとおりです。
{ "case1": {
"search_string": "testing",
"expect_string": "Testing"
},
"case2": {
"search_string": "testing",
"expect_string": "Testing"
}
}
次に、test_baidu.pyを更新します。更新されたコードは、次のとおりです。
from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
@ddt
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
# 此处测试数据从文件读取,使用@file_data装饰器
# 文件路径是相对于Baidu这个测试类的相对路径
# 使用外部文件方式Load数据无须使用unpack
@file_data('test_baidu.json')
def test_baidu_search(self, search_string, expect_string):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").send_keys(search_string)
driver.find_element_by_id("su").click()
time.sleep(2)
search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
print(search_results)
self.assertEqual(expect_string in search_results, True)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main(verbosity=2)
ご覧のとおり、@ file_dataデコレータの使用は、@ dataデコレータの使用とは少し異なります。
-
@file_dataデコレータでは、ファイルのパスはテストクラス自体を基準にしています。この例では、テストクラスBaiduが配置されているファイルの相対位置です。
-
同じデータセットに複数のパラメーターがある場合でも、@ file_dataを使用する場合はunpackを使用する必要はありません。
上記の例でYAMLファイルを使用する場合は、次の点に注意する必要があります。
-
Pythonでyamlファイルを使用する場合は、PyYAMLをインストールする必要があります。
-
インストールコマンド:pipinstallpyyamlまたはpython-m pip install pyyaml
インストール後、test_baidu.jsonの同じディレクトリに次の内容のファイルtest_baidu.yamlを作成します。
"case1":
"search_string": "testing"
"expect_string": "Testing"
"case2":
"search_string": "testing"
"expect_string": "Testing"
次に、test_baidu.pyを変更します。変更されたコンテンツは、次のとおりです。
from ddt import ddt, data, file_data, unpack
from selenium import webdriver
import unittest
import time
# 使用yaml文件前先尝试导入,导入失败则将skip使用yaml数据驱动的测试用例
try:
import yaml
except ImportError:
have_yaml_support = False
else:
have_yaml_support = True
needs_yaml = unittest.skipUnless(
have_yaml_support, "Need YAML to run this test"
)
@ddt
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
# 使用yaml文件必须使用@needs_yaml装饰
@needs_yaml
@file_data('test_baidu.yaml')
def test_baidu_search(self, search_string, expect_string):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").send_keys(search_string)
driver.find_element_by_id("su").click()
time.sleep(2)
search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
print(search_results)
self.assertEqual(expect_string in search_results, True)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main(verbosity=2)
ご覧のとおり、JSONファイルを使用する場合とは異なり、YAMLファイルを使用するにはPyYamlを最初にインストールする必要があります。次に、yamlのインポートの失敗を防ぐために、needs_yamlデコレーターを定義して、プログラムに安全性の判断を追加しました。
インポートが失敗した場合、needs_yamlで装飾されたすべてのテストケースは実行されません。
(4)ddtはファイルを使用してデータを提供します。ddtは
デフォルトでJSONおよびYAML形式のデータのみをサポートするため、他の形式のデータファイルです。しかし、他のデータ形式を使用したい場合はどうなりますか?
一般的に使用される方法は次の2つです。
-
最初に他の形式(Excel形式など)でファイルを読み取り、次にddtでサポートされるJSONまたはYAMLファイルを作成し、最後に取得したデータをこのファイルに書き込んでから、@ file_data();を使用します。
-
関数を作成し、他の形式でファイルを読み取り、関数でデータを取得して、@ ddt.data()でサポートされている形式にデータを直接返します。
[The Way of Infinite Testing]パブリックアカウントへの注目、[リソースの受信]への返信、
Pythonプログラミング学習リソースの乾物、
Python + AppiumフレームワークAPPUI自動化、
Python + Seleniumフレームワーク
WebUI自動化、Python + UnittestフレームワークAPIへようこそオートメーション、
リソースとコードは無料で送信されます〜
記事の下部に公式アカウントのQRコードがあります。WeChatでスキャンしてフォローするだけです。
備考:私の個人公開アカウントが正式に開設され、ビッグデータテスト、機能テスト、テスト開発、APIインターフェイスの自動化、テストの運用と保守、UI自動化テストなどのテストテクノロジーの共有に専念しています。WeChat検索パブリックアカウント:「WuliangThe Way of Testing」、または以下のQRコードをスキャンしてください。
注意を向けて、一緒に成長しましょう!