Python functional programming series 008: Testability

cube root 2021-10-29 02:14:24
python functional programming series testability

In our previous article , Many of the advantages of functional programming have been repeatedly emphasized , For example, the ability to express , The benefits of deferred Computing . But a bigger one is actually testability . This article is also the core of the whole series , We don't want to completely eliminate the process 、 Side effects, etc , But limited use , And can make improvements on the basis of existing code .

origin

below , Let's look at an example : A company wants to design a time-based scheduler , They can provide a better than crontab Better grammar , For example, it can be based on the first three days of each month 、 Weekly weekend 、 The first day of the second week of each month . When designing this scheduler , It will involve many functions of time , such as , Here is a possible function to implement :

from datetime import datetime, timedelta
def yesterday_str() -> str:
""" Get the string of yesterday's time (YYYYMMDD)
"""
return (
datetime.now() - timedelta(days=1)
).strftime("%Y%m%d")

This is the most intuitive implementation , however , This function is found to be unmeasurable . You should see the reason , Because of datetime.now() It has side effects . Specifically, we can give examples of possible problems in the test as follows :

Problems in unit test examples

How do we write the unit test of this function , Obviously , Most people would write that :

def test_yesterday_str():
assert yesterday_str() == (
datetime.now() - timedelta(days=1)
).strftime("%Y%m%d")

Obviously , This unit test reveals several problems at a glance :

  1. in fact , We just rewrote the original code , There is no real test .
  2. Even if we admit this way of writing , There is also a certain probability that near the early morning (23:59:59 seconds ), The test failed , But this is not an error caused by the problem of function implementation .

Problems in integration testing

In the actual test , Maybe some parts of the integration are more difficult to test , For example, let's the next function that calls the above function , Its function is every month 1 No. 1 performs a task :

def run_at_first_day():
if yesterday_str()[-2:] == '01':
do_something()

This example not only passed on the side effects step by step , And in the test , If we weren't 1 Test No , We can only measure do_something Not measured by logic run_at_first_day The logic of this scheduling . And you can imagine , In this system , There will be many such examples .

How to solve

General solutions

Conventional solutions , The first is to modify the system time .Python There is one of them. FreezeGun Module , Is to do something similar :

from freezegun import freeze_time
import datetime
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)

Of course , The solution is for Time It's all right , We may have more than one side effect , It may be reading the configuration 、 Database interaction and so on , This solution can't solve these things .

The other is the concept of testing field , such as fakemockstub Such concepts , Of course, we will also use it in the following work fake The concept of , But there is no need to dwell on these complex concepts .

Take the side effect function as a parameter

Let's rewrite it in the following way , You find that the whole function becomes measurable :

def yesterday_str(now_func = date.now) -> str:
assert yesterday_str() == (
now_func() - timedelta(days=1)
).strftime("%Y%m%d")

The specific test method is as follows :

def fake_now(now_str):
def helper():
return datetime.strptime(now_str, "%Y-%m-%d")
return helper
def test_yesterday_str():
return yesterday_str(fake_now('2020-01-01')) == '2019-12-31'

We find that there are many advantages to writing like this :

  1. The whole function becomes no side effects , Side effects are isolated in the parameters
  2. Because there are no side effects , We just need to make the corresponding 「 false 」 Function can simulate the input to be , Especially for Void -> A This type of function .
  3. We can simulate the operation of any state by means of pseudo function , This makes the scheduling logic we mentioned above testable .
  4. When we specifically call , Because the default value of the parameter is set , Therefore, the specific method of use has not changed .

This method of writing side effects in parameters , We will encounter a similar solution later ( Random numbers without side effects ), And see in subsequent articles Monad How to solve such problems .

however , This article extends 「 Testability 」 The concept of , Generally speaking , Functions without side effects are absolutely measurable , And the test can be completed in the unit test phase . Functions with side effects / Methods make testing difficult . therefore , Through the concept of unit test and coverage , We can expose most of the problems before going online , It's very Fancy One way . If you add type derivation , The judgment of the availability of this system will be more perfect ( Of course , This is a Python This language is hard to do , But it can be based on mypy Do something similar ).

Of course , This is also the beginning of functional programming testing , We will introduce another unique testing concept of functional programming later —— Property based testing (Property-based testing), Then it introduces some good third-party modules and methods inspired by it .

版权声明
本文为[cube root ]所创,转载请带上原文链接,感谢
https://pythonmana.com/2021/10/20211013140442388o.html

  1. 预备知识-python核心用法常用数据分析库(下)
  2. python 文件排版,怎么控制写入在对应文件的位置(要写吐了,真是服了)
  3. Preliminary Knowledge - Python Core use Common Data Analysis Library (ⅰ)
  4. Typographie de fichiers Python, comment contrôler l'écriture à l'emplacement du fichier correspondant (pour écrire et vomir, vraiment pris)
  5. python:例题求解,不知道怎么等输入完所有数字后再输出
  6. 用python来实现:根据实际查询结果补充完整数据
  7. Mise en œuvre en python: compléter les données complètes en fonction des résultats réels de la requête
  8. python对excel进行分组但不进行聚合统计操作,且输出到不同的表格中?
  9. Python regroupe Excel, mais n'effectue pas de statistiques agrégées, et l'affiche dans différents tableaux.
  10. python如何提交,不要用太复杂的函数
  11. Comment soumettre Python sans utiliser de fonctions trop complexes
  12. Python,数据文件操作问题,想要代码
  13. python 提取多个字符串中的多个字段
  14. python 读入用户输入的一组正整数,到-1结束
  15. Python lit un ensemble d'entiers positifs entrés par l'utilisateur, se terminant par - 1
  16. 测试逐飞的MM32F3277 MicroPython开发板的基本功能
  17. Python timer reference
  18. 关于#python#的问题:python3队列维护
  19. Developing Hongmeng equipment program using python (3-prototype of security system)
  20. Questions sur # # Python #: maintenance de la file d'attente Python 3
  21. 怎么用Python打印数字三角
  22. 怎麼用Python打印數字三角
  23. Comment imprimer un triangle numérique en python
  24. Tester la fonctionnalité de base du tableau de développement microspython mm32f3277 Flying - by - flying
  25. Python extrait plusieurs champs de plusieurs chaînes
  26. Pandas核心用法
  27. Utilisation centrale de pandas
  28. Python, problème de fonctionnement du fichier de données, Code désiré
  29. 【78技术人社群~Python分部】,就在今天成立 →
  30. 社区共读《Python编程从入门到实践》第一天阅读建议
  31. La communauté lit les recommandations de lecture pour la première journée de la programmation Python de l'introduction à la pratique
  32. [78 Communauté des technologues ~ Division Python], fondée aujourd'hui →
  33. Pandas核心用法
  34. 您好,请问您的python按钮开了线程处理还卡ui的问题解决了吗
  35. Python: résolution d'exemples, je ne sais pas comment attendre que tous les chiffres soient entrés avant de sortir
  36. Bonjour, puis - je vous demander si votre bouton Python est activé pour le traitement du thread et le retour de l'interface utilisateur de la carte a été résolu?
  37. Utilisation centrale de pandas
  38. Python technique 2: advanced usage of function parameters
  39. OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)
  40. OpenCV-Python實戰(14)——人臉檢測詳解(僅需6行代碼學會4種人臉檢測方法)
  41. OpenCV - Python Real play (14) - face detection details (six lignes de code seulement pour apprendre 4 méthodes de détection de visage)
  42. 你好,python开发mes系统,能分享下吗,我最近也想搞这方面的
  43. 你好,python開發mes系統,能分享下嗎,我最近也想搞這方面的
  44. Bonjour, Python a développé mon système, pouvez - vous le partager?
  45. Introduction to tuples in Python
  46. Introduction to strings in python (Part 2)
  47. Introduction to strings in python (Part 1)
  48. python关于 if 的简单操作时,输出结果不是预期所要的结果 的问题
  49. python關於 if 的簡單操作時,輸出結果不是預期所要的結果 的問題
  50. Lorsque Python fonctionne simplement sur if, la sortie n'est pas le résultat attendu
  51. Python中字典问题请求解惑
  52. Python中字典問題請求解惑
  53. Demande de résolution de problèmes de dictionnaire en python
  54. Python中字典问题请求解惑
  55. Python technique 2: advanced usage of function parameters
  56. Demande de résolution de problèmes de dictionnaire en python
  57. Preliminary Knowledge - Python Core use Common Data Analysis Library (ⅱ)
  58. 关于python的代码问题,终端打印为什么会起飞
  59. En ce qui concerne les problèmes de code Python, pourquoi l'impression du terminal décolle - t - elle?
  60. Python中种子seed的运用问题