令我震惊的是,很少有开发人员了解综合测试。
我经常收到开发人员发来的电子邮件,担心他们缺乏测试经验。说实话,他们应该担心!测试是没有商量余地的。
顶级公司——以及我工作过的所有工程团队——都遵循千层面测试策略。
他们不仅仅依靠一种类型的测试来确保代码正常工作。
任何新版本都必须经过层层考验。所有这些都是为了生产具有最少错误的可预测软件。
这就是我的意思……
基础层:单元测试
首先,您要确保您的各个函数和类按照您期望的方式运行。
单元测试是任何分层测试策略的基础。
通过编写全面的逻辑测试,您可以对自己的代码充满信心。好处是您可以在将来快速运行单元测试,以便在出现问题时立即提醒您。
这里有一些(非常愚蠢的)单元测试:
import unittest
from typing import Optional
def hello(name: Optional[str] = None) -> str:
if name:
return f'Hello {name}'
return 'Hello world'
class TestHello(unittest.TestCase):
def test_hello(self):
self.assertEqual(hello(), 'Hello world')
def test_hello_name(self):
self.assertEqual(hello('John'), 'Hello John')
def test_hello_empty_string(self):
self.assertEqual(hello(''), 'Hello world')
他们检查我的函数是否产生了我期望的结果。
对于您编码的每个新功能,您还应该编写许多单元测试。即使是这个简单的hello()
功能,我也写了 3 个单元测试!如果您正在编写更复杂的生产软件,您应该从不同角度编写大量测试。
单元测试应该快速且数量众多。每个测试应该只测试代码的单个“单元”中的代码。不要在单元测试中测试服务之间的交互或复杂的用户流。
干净、简单且易于理解。
中间层:功能/集成测试
接下来,我们为测试增加了更多的复杂性和开销。
我们测试不同服务、数据库和内部 API 之间的交互。这些测试更难编写且运行成本更高。他们要求应用程序的多个部分在测试时正在运行。
与单元测试相比,您的功能/集成测试会更少。您不应该使用它们来广泛测试单个服务的输出。相反,您应该测试服务是否按照您期望的方式进行交互。
集成测试确保两个服务可以连接并在它们之间交换数据。它可能会在交互过程中断言有关服务中间状态的数据。
这是一个集成测试:
def test_database_insert_from_orm():
db_objects = MyModel.objects.all()
assert len(db_objects) == 0
response = requests.post('/api/my_model', {'name': 'New Test Model'})
assert response.status_code == 201
db_objects = MyModel.objects.all()
assert len(db_objects) == 1
查看它如何与数据库交互,然后使用 API 插入对象并测试它是否存在?我们正在测试API 和数据库之间的集成。
功能测试更侧重于用户流程或业务用例。它不经常测试中间状态。相反,它关注一组给定的请求是否产生了预期的最终结果。
总之,这个中间层仍然允许您隔离应用程序的某些部分进行测试,同时忽略其他部分。但这些测试比单独的详细单元测试更广泛、更复杂。
外层:端到端测试
这是运行起来最困难和最昂贵的测试类型。但最终,它最能告诉您应用程序中真实用户将看到的内容。
对于端到端 (E2E) 测试,您运行整个应用程序。启动所有服务。让一切运行起来。
然后,您使用测试软件(如Cypress或Selenium)来自动化测试用户。您编写代码来告诉自动化用户采取某些操作,例如在您的应用程序周围单击、登录和执行常见的工作流程。
最后,您断言用户看到了他们应该看到的屏幕。确保页面上呈现的内容符合您的预期。
这些测试编写起来很棘手,如果应用程序的任何部分发生变化,它们可能会不稳定。尽管如此,他们还是值得为正确而付出努力。没有其他类型的测试能让您确信用户会看到正确的结果。
为什么层次很重要
单元测试非常适合细节。他们检查逻辑、实现和语法中的错误。你用单元测试覆盖了大量的基础,它们是最容易上手的。但是,它们无法告诉您复杂应用程序中不同服务之间的交互。
集成测试在确保应用程序的各个部分以您期望的方式相互通信方面非常出色。您可以在每一步断言有关应用程序状态的各种事情。但它们运行速度较慢,有时难以编写,而且不适合测试小细节或大局。
端到端测试真正着眼于全局。他们告诉你一些非常重要的事情——用户在使用应用程序时会看到什么。您可以使用一些出色的 E2E 测试来自动化大部分现有的手动测试。然而,它们更难编写且运行更慢!更重要的是,您不能断言太多关于数据库或底层代码的状态。就是用户看到的。
一起,而且只有一起,您才能全面了解您的应用程序。您可以通过编写多种不同类型的测试来获得对软件的信心。
救了我的项目
就在本周,一项 E2E 测试在我的代码中发现了单元测试和集成测试遗漏的错误!
当我发现这个错误时,我立即为它编写了一个单元测试(这样我们就可以更早地发现它,而无需运行缓慢、昂贵的 E2E 测试)。但是如果没有我们的自动化单元测试步骤来阻止它,这个错误就会进入生产!
测试是一个非常重要的话题。最好的开发人员了解测试以防止生产中出现问题的价值。此外,出色的测试可以加快新开发的速度。您可以隔离代码中的更改并快速重新运行测试,以深入了解您的更改是否破坏了其他任何东西。
这篇文章只是触及表面。想了解更多关于测试的信息?给我回信。
每日清单
我每天早上都会为软件开发人员写一些新东西。
如果你喜欢我的文章,点赞,关注,转发!