PyTest:參數化簡介

使用參數化功能為Python軟件包編寫非常簡潔的單元測試的指南。

PyTest:參數化簡介

第一部分將說明隨附軟件包的結構以及如何在您的系統上進行設置。 如果您只想查看PyTest中的參數化示例,則可以直接跳至第二部分"參數化測試"。

包裝結構和設置

克隆的存儲庫將包含一個名為efficiency_dedup的包和一個包含測試用例的tests文件夾。

該軟件包旨在在Python列表中執行有效的重複數據刪除(刪除重複值)。 它分兩個步驟執行此操作-首先,對列表進行排序,然後使用一種重複數據刪除算法對已排序的列表進行重複數據刪除。 請注意,此軟件包僅用於說明; 因此,許多代碼在功能上是多餘的。 這是包的結構:

efficient_dedup
|
| - efficient_deduplication
| - deduplication_algorithms
| - sorting_algorithms
|
| - tests
|
| - test_efficient_deduplication

它基於策略設計模式。 高效重複數據刪除模塊中定義的EfficientDeduplicator類是上下文:

<code>from .deduplication_algorithms import DeduplicationAlgorithm
from .sorting_algorithms import SortingAlgorithm

class

EfficientDeduplicator

:

def

__init__

(

self

,

sorter:

SortingAlgorithm,

deduplicator:

DeduplicationAlgorithm)

:

self

.__sorter = sorting_algorithm

self

.__deduplicator = deduplication_algorithm

def

deduplicate_efficiently

(

self

, list_to_deduplicate)

:

return

self

.__deduplicator.deduplicate(

self

.__sorter.sort(list_to_deduplicate))/<code>

要求每個deduplication_algorithms和sorting_algorithms模塊都實施策略。

在sorting_algorithms模塊中僅定義了兩種策略行為,它們都封裝在一個類SortingAlgorithm中。 您可以通過將反向參數設置為True或False來選擇所需的特定行為:

<code>

class

SortingAlgorithm

:

def

__init__

(

self

, reverse=False)

:

self

.__reverse = reverse

def

sort

(

self

, list_to_sort)

:

if

self

.

__reverse:

list_to_sort.sort(reverse=True)

else:

list_to_sort.sort()

return

list_to_sort/<code>

deduplication_algorithms模塊包含四個不同的實現,每個實現封裝在一個不同的類中。 第一個類DeduplicationAlgorithm充當其他三個實現的基類(這不是實際的代碼,因為此處省略了函數的定義):

<code>

class

DeduplicationAlgorithm

:

def

deduplicate

(

self

, list_with_duplicates)

:

return

class

HashSetDeduplicationAlgorithm

(

DeduplicationAlgorithm

):

def

deduplicate

(

self

, list_with_duplicates)

:

return

class

CustomComparisonDeduplicationAlgorithm

(

DeduplicationAlgorithm

):

def

__init__

(

self

, comparison_fun=lambda x,

y:

x == y)

:

self

.__comparison_fun = comparison_fun

def

deduplicate

(

self

, list_with_duplicates)

:

return

class

LookaheadCustomComparisonDeduplicationAlgorithm

(

DeduplicationAlgorithm

):

def

__init__

(

self

, lookahead_window_size=

100

, comparison_fun=lambda x,

y:

x == y)

:

self

.__lookahead_window_size = lookahead_window_size

self

.__comparison_fun = comparison_fun

def

deduplicate

(

self

, list_with_duplicates)

:

return

/<code>

要運行測試用例,將cd放入軟件包的根文件夾並運行以下命令:

> cd /efficient_dedup> python -m pytest

參數化測試

因此,在繼續操作之前,讓我們先進行總結。 我們有一個稱為EfficientDeduplicator的上下文類,它需要兩種策略:SortingAlgorithm和DeduplicationAlgorithm。 該上下文類僅具有一個功能,即deduplicate_效率地。

我們希望使用策略的所有可能組合以及一些不同的測試數據來高效地測試重複數據刪除。 正如我們將看到的,如果使用參數化,則可以在一個測試用例中完成所有這些工作。

數據參數化

這是我們可以編寫的最基本的測試用例:

<code>

def

test_deduplicate_efficiently(self):

sorter

=

SortingAlgorithm(

reverse=False

)

deduplicator

=

LookaheadCustomComparisonDeduplicationAlgorithm(

lookahead_window_size=100,

comparison_fun=lambda

x,

y:

x

==

y

)

efficient_deduplicator

=

EfficientDeduplicator(sorter,

deduplicator)

list_with_duplicates

=

[1,

2

,

2

,

7

,

4

,

8

,

9

,

3

,

5

,

4

,

6

,

3

,

1

,

7

,

3

,

3

]

assert

set(efficient_deduplicator.deduplicate_efficiently(list_with_duplicates))

==

set(list_with_duplicates)

/<code>

假設我們要使用幾種可能的輸入(即,變量list_with_duplicates的幾種不同值)來執行此測試。 首先,我們在測試函數中使list_with_duplicates為參數。 然後,我們通過@ pytest.marker.parametrize裝飾器提供該參數的值列表。

<code> 

@pytest.mark.parametrize('list_with_duplicates',

[

[1,

2

,

2

,

7

,

4

,

8

,

9

,

3

,

5

,

4

,

6

,

3

,

1

,

7

,

3

,

3

],

[1,

2

,

3

,

5

,

7

,

9

,

4

,

7

,

8

],

[1,

1

,

1

,

1

,

1

,

1

,

1

,

1

,

1

]

])

def

test_deduplicate_efficiently_w_data_parametrization(self,

list_with_duplicates):

sorter

=

SortingAlgorithm()

deduplicator

=

DeduplicationAlgorithm()

efficient_deduplicator

=

EfficientDeduplicator(sorter,

deduplicator)

assert

set(efficient_deduplicator.deduplicate_efficiently(list_with_duplicates))

==

set(list_with_duplicates)

/<code>

這是在Pytest中進行參數化的一般過程:

· 您可以在測試函數的參數列表中指定要參數化的變量

· 然後,使用@ pytest.marker.parametrize裝飾器提供變量值的列表。

類的參數化

現在,假設我們想對DeduplicationAlgorithm的所有可能的不同實現運行基本測試,但要保持數據不變。 這可以通過Pytest參數化,Python的inspect模塊以及類在Python中是一等公民的巧妙組合來實現(這意味著它們可以作為函數的參數傳遞)。

要獲取deduplication_algorithms模塊中所有類的列表,我們可以導入該模塊,然後運行以下代碼:

<code>

print([

name)

for

name, obj

in

inspect.getmembers(deduplication_algorithms)

if

inspect.isclass(obj)

])

/<code>

這為我們提供了模塊中的類的列表:

[, ,,]

然後我們可以將其傳遞給@ pytest.marker.parametrize裝飾器:

<code>

@pytest.mark.parametrize('deduplication_algorithm_class',

[

getattr(deduplication_algorithms,

name)

for

name,

obj

in

inspect.getmembers(deduplication_algorithms)

if

inspect.isclass(obj)

])

def

test_deduplicate_efficiently_w_class_parametrization(self,

deduplication_algorithm_class):

sorter

=

SortingAlgorithm()

deduplicator

=

deduplication_algorithm_class()

efficient_deduplicator

=

EfficientDeduplicator(sorter,

deduplicator)

list_with_duplicates

=

[1,

2

,

2

,

7

,

4

,

8

,

9

,

3

,

5

,

4

,

6

,

3

,

1

,

7

,

3

,

3

]

assert

set(efficient_deduplicator.deduplicate_efficiently(list_with_duplicates))

==

set(list_with_duplicates)

/<code>

等等。 您已經在Pytest中實現了類參數化!

結合數據和類參數化

Pytest的一個很棒的功能是,如果在一個測試函數上堆疊許多@ pytest.marker.parametrize裝飾器,它將自動為所有裝飾器(如固定產品)上的所有可能組合運行測試。 最後,我們將使用此功能在單個測試用例中結合上述兩個參數; 實際上,我們還將對SortingAlgorithm的reverse屬性進行參數化:

<code>

@pytest.mark.parametrize('list_with_duplicates',

[

[1,

2

,

2

,

7

,

4

,

8

,

9

,

3

,

5

,

4

,

6

,

3

,

1

,

7

,

3

,

3

],

[1,

2

,

3

,

5

,

7

,

9

,

4

,

7

,

8

],

[1,

1

,

1

,

1

,

1

,

1

,

1

,

1

,

1

]

])

@pytest.mark.parametrize('sorting_algorithm_reverse_option',

[

True

,

False

])

@pytest.mark.parametrize('deduplication_algorithm_class',

[

getattr(deduplication_algorithms,

name)

for

name,

obj

in

inspect.getmembers(deduplication_algorithms)

if

inspect.isclass(obj)

])

def

test_deduplicate_efficiently_w_data_and_class_parametrization(self,

list_with_duplicates,

sorting_algorithm_reverse_option,

deduplication_algorithm_class):

sorter

=

SortingAlgorithm(reverse=sorting_algorithm_reverse_option)

deduplicator

=

deduplication_algorithm_class()

efficient_deduplicator

=

EfficientDeduplicator(sorter,

deduplicator)

assert

set(efficient_deduplicator.deduplicate_efficiently(list_with_duplicates))

==

set(list_with_duplicates)

/<code>

這是您要克隆的軟件包中測試用例的最終形式。 如果您詳細運行Pytest:

> python -m pytest -v

您將觀察到這樣的輸出:

tests/test_efficient_deduplication.py::TestEfficientDeduplicators::test_deduplicate_efficiently[DeduplicationAlgorithm-True-list_with_duplicates0]
PASSED [33%]

上面輸出中的第二行列出了測試用例中使用的參數的確切組合。

結論

使用本文中介紹的技術,將來可以編寫更簡潔有效的Python測試用例!

要克隆本文隨附的源代碼,請私信譯者。

(本文翻譯自Rishabh Malviya的文章《PyTest: An Introduction to Parametrization》,參考:https://levelup.gitconnected.com/pytest-an-introduction-to-parametrization-2b27bebb6d4b)


分享到:


相關文章: