假装直到你成功

您所在的位置:网站首页 typora写python代码 假装直到你成功

假装直到你成功

2023-03-29 06:37| 来源: 网络整理| 查看: 265

_得到它?因为我们在嘲笑东西?_无论如何。

编写测试。不是很多。主要是集成。 - Kent C. Dodds - Guido van Rossum

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--hFmRywbJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/8ies2yfjwzp28uhgwo20.png)

你玩过龙与地下城吗?我已经尝试了几次,但至少聚会中的人似乎无法像我一样投入。这很糟糕。我希望一旦这一切都过去了,我可以再次亲自尝试比赛。无论如何,我问的原因是,你有没有觉得自己像电影中的角色?一场比赛怎么样?一本书? d&d 运动?你是地下城主还是玩家?你到底是谁_?我真的累了。现在才星期二(在写第一次迭代时),我已经筋疲力尽了。可能会慢慢失去理智。

无论如何,在本周的竞选冒险中...lab,我们正在试验单元测试和持续集成,这是我整个学期都在等待的实验室。我一直很喜欢 devops 方面,因为我一直在修补硬件或新的软件应用程序,而且我也一直想做一些软件测试,所以很自然地,我很兴奋。

我们要将单元测试集成到我们的个人项目中,添加单元测试,将单元测试添加到另一个学生的项目中,最后将 CI 添加到我们的 GitHub 存储库中。

当然,第一步是研究 Python 的测试框架(因为我的项目是用 Python 编写的。)我实际上发现 Python 有一个内置的单元测试框架,创造性地命名为unittest......好吧,至少它不是描述性的愚蠢聪明但相关的名字。所以我从那个开始,但我发现语法和输出有点笨拙,所以我决定看看新的热点是什么:输入Pytest。 (老实说,我之所以选择它,是因为 reddit 上的一些家伙告诉我它很棒。我是一个新手学生,起诉我。)

我开始了我的冒险,做hello world的单元测试,效果很好。然后我尝试将我的学习应用到我的项目并设置我的环境,这就是我遇到了一些关于 Python 如何构建其目录和代码的奇怪问题的地方。你看,Pytest 以某种方式喜欢事物。测试文件名必须以test_前缀开头,目录必须包含__init__.py文件,并且测试不能位于高于您测试的目录的目录中(例如,测试不能位于源文件夹中的文件夹中......这似乎违反直觉,唉,Python 和查尔斯·曼森一样稳定 (好莱坞往事很精彩,去看看吧。))我还必须做一些奇怪的 hack,我还没有想出一个解决方法,因为Python 大喊它有时找不到库,有时却可以。设置好环境后,我开始进行一些测试。

我决定首先为我的项目中的一个小文件加载器功能编写一个测试。该函数接收两个文件:一个包含用于检查其状态的链接的 HTML 页面,以及一个您不想在 HTML 文件中检查其状态的链接的文本文件。所以我认为第一个测试看看这个函数是否真的按预期工作是给它坏文件来检查。

def test_file_check_ignored_empty_files(): with pytest.raises(FileNotFoundError): fio.file_check_ignored("", "")

进入全屏模式 退出全屏模式

如果发生这种情况,该函数会打印一条消息并抛出一个错误......那么,为什么我的测试没有显示呢?事实证明,如果你想抛出一个特定的错误,你实际上需要调用raise......在我的函数中修复了这个问题,测试现在可以正常运行。惊人的!现在让我们进行测试以确保输出匹配,即该函数实际上可以正常工作:

def test_file_check(): tested_output = '\n\n\n\nHeader\n\n\n\n Working link here \n However, this line (and link) should be ignored. \n\n\n' soup = fio.file_check("tests/test1.html") assert str(soup) == tested_output

进入全屏模式 退出全屏模式

这是我们要比较的实际 HTML:

Header Working link here However, this line (and link) should be ignored.

进入全屏模式 退出全屏模式

伟大的!这个匹配 HTML 并通过,这意味着该函数正确读取了文件。如果文件的处理方式出现任何问题,此测试将通知我们,因为输出存在差异导致测试失败。现在让我们转向更有趣的事情:模拟网络响应以确保程序实际上将 404 响应读取为 404 响应,但首先我们必须了解一下固定装置是什么,以及一些关于猴子的知识。

固定装置有点像_环境_。夹具将在测试运行之前设置,因为每个功能都必须在可重复但相同的测试环境中进行测试。例如,如果我们正在测试向网站添加帖子的功能,我们必须设置环境以模拟插入数据库的帖子,以便所有相关信息(发布时间、日期、帖子内容等) ) 关于这篇文章的内容可以计算和测试。本质上,我们必须将世界设置为特定状态,然后进行测试,然后在测试后返回原始状态。为了正确使用我们的fixture,我们必须_monkeypatch_我们的测试。

Monkeypatching 是在运行时动态更改程序的一部分,以便在测试时反映环境条件。如果一个夹具就像为测试创建一个房间,那么猴子补丁将装饰房间,因此被测试的猴子每次都有相同(且有用)的体验。你是猴子。回去工作。 Monkeypatching 对于模仿(模拟)外部库调用特别有用。那么回到手头的任务,我们如何让我们的程序_认为_它正在测试一个网站?很容易:我们创建了一个模拟不成功的响应调用 (404.) 的环境:

创建一个包含 status_code 成员等于 404 的类(我们想要的响应代码。)

创建一个调用该类的函数

将 requests 库中的.get方法的响应设置为使用mock_get代替(退出函数后将重置为正常)

正常调用我们的函数,看看响应码是不是404(剧透:是因为我们规定的。)

以下是实际效果:

import requests def test_get_request_404(monkeypatch): """ Monkeypatches a version of hdj_linkchecker.py's single_link_check() function, suchthat the request is always 404 for a given link. """ # Create a mocked object with an http status_code of 404. class MockResponse: def __init__(self): self.status_code = 404 # Serve the object when called using a monkeypatch def mock_get(url): return MockResponse() # Create a monkeypatch fixture monkeypatch.setattr(requests, "get", mock_get) assert lc.single_link_check("https://google.ca") == 404

进入全屏模式 退出全屏模式

这是正在测试的实际功能:

def single_link_check(url): req = requests.get(url) return req.status_code

进入全屏模式 退出全屏模式

有趣的是,测试函数最终比实际函数长 4 倍。

酷,这样就行了。我们可以尝试将 404 更改为其他内容,例如 666,虽然它在本质上是天堂般的,但实际上并不是真正的响应代码。使用 666 会使测试失败,因为我们的 monkeypatch 现在断言的内容与预期的不同。

现在有了我们的方式,时间为storytime:

在一个相对晴朗、有点暗的夜晚,这个夜晚非常特别,也不是很不祥,一个学生(满头头发)开始测试另一个功能。他很快就撞到了一堵砖墙上:“为什么!你为什么不按你应该的方式删除链接??”他尖叫起来。你看,这个函数有一个简单的工作(或者他认为):获取一个链接列表,如果它与链接匹配,则从 html 文件中删除一个链接,然后测试剩下的任何内容。 “那你为什么不删除任何链接?正常调用时你工作得很好!”但是你看,亲爱的汉夫,他被骗了,因为另一个功能被创造出来了。在魔多多伦多的土地上,在末日山塞内卡学院的大火中,黑魔王索伦......呃等等,没关系。实际上还有另一个函数一起包裹了这个函数并进行了删除......所以这个函数自然会返回与输入相同的输出,它所做的只是返回链接。不要删除它们。 “我的狂妄自大。我的贪婪。”他一边想,一边诅咒写这个程序的傻瓜。这个故事的寓意,你_真的_应该知道你的程序是如何工作的。

tl;dr:如果你编写了一个执行 x 的函数并且有另一个执行 y 的函数,请为 x 编写一个测试,而不是盲目地接近 y。也为 y 写一个,只要确保你测试的是实际输出而不是你认为应该输出的输出。

所以这就像浪费了2个小时。本来可以看指环王的。或者看漂亮的图表。

说到漂亮的图表,让我们生成一个代码覆盖率报告,看看我们做了多少(little?)工作。令人惊讶的是,我认为 Pytest 会内置此功能,但它依赖于一个名为pytest-cov的外部库,它可以做一些非常简洁的事情,例如将报告导出为 HTML 以便稍后发布。 涂鸦下来...

现在安装库后,我运行pytest --cov-report term-missing --cov=src tests/以在我的src目录上生成覆盖率报告:

令人惊讶的是,PyCharm 有一个内置的覆盖工具,它会在左侧的文件资源管理器窗格中显示测试覆盖了多少源代码(只需右键单击测试文件夹并点击Run 'pytest' in tests)。我还在 PyCharm 中添加了几个项目配置,因此右键单击任何测试文件可以运行它并显示输出,而不是打开控制台并输入pytest(尽管我还为此添加了一个按钮,可以用shift+f10切换) .

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--5ojTA9tZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/spx5rkl9hz80nrscom0i.png)

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s---S07ZQ-a---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https:// /dev-to-uploads.s3.amazonaws.com/i/jw0oxazgmog8cvsw4rwb.png)

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--XI9c3jqr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/f4tsckh06jg06xq0u2fe.png)

天哪,这狗屎太酷了。

凉爽的。现在我们有一些测试和覆盖率报告。下一步是什么?好吧,让我们在我们的 repo 中添加一个 GitHub 操作,这样我们就可以在每次对我们的代码发出拉取请求时运行这些测试。

坦率地说,这个过程非常简单。老实说,这很容易令人失望。我只是转到我的 repo 上的 Actions 页面并为我的 Python 应用程序添加了一个工作流:

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--h4S5cJxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/kljfab3aonibiyjsftzx.png)

然后它生成了一个python-package.yml文件,我根据自己的喜好对其进行了定制。我指定仅使用 Python 3.6、3.7、3.8 和 3.9,因为我的项目将使用的最低版本是 Python 3.6。我还告诉操作在每次提交时运行flake8、black和pytest:

# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Python package on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 pytest if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Code Format with black run: | # stop the build if there are any code formatting issues black --check . - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | pytest

进入全屏模式 退出全屏模式

然后我简单地将它推送到我的仓库,就像魔术一样,它起作用了:

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--rExVCIh9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/7241bqio91npxohmpnbv.png)

呜呼。

实际上,我在进行任何测试之前就设置了它,这促使我被 GitHub 发送垃圾邮件,说我所有的测试都失败了,哈哈。它失败的原因是因为我没有测试......duh。但是,一旦我完成了甜蜜、甜蜜的变基、合并、提交和推送,它就开始运行我的测试并给出美味的绿色复选标记✔️。

随着一切更新和工作,我的最终任务是更新我的CONTRIBUTING.md文件,以便其他开发人员知道我的项目的结构以及测试的工作方式。

完成我的项目后,现在是时候将测试添加到另一个学生的项目中了。是时候去打旧的 Plamen 以获得更多 Java 体验了。

我不太确定从哪里开始测试Plamen 的链接检查程序,因为自从他和我上次合作以来它已经发生了很大变化。在快速复习后,我看到他的项目的很大一部分没有经过测试(特别是参数解析器)。由于我在之前的实验室中从事过这项工作,因此我对它的工作原理相当熟悉,但我确实要求复习一下。

在课堂上,我正在测试fileArgParser和urlArgParser函数。自从 Plamen 在实验室 6 中重构了他的代码后,他将它们移到了另一个文件中并进行了一些修改。现在函数需要传入WebDriver参数,所以我认为我需要模拟WebDriver。我不得不与他讨论一下这种方法。

很难找出如何准确地模拟WebDriver的所有属性,但我认为我只需要使用默认的“模拟”属性传递它,因为它没有用于解析参数的实际逻辑。我实际上在我自己的项目在这里中做了类似的事情。我在谷歌上快速搜索了如何模拟WebDriver并找到这个。基本上,在运行测试之前,函数createMocks()会模拟WebDriver:

@Before public void createMocks() { webdriver = mock(WebDriver.class); }

进入全屏模式 退出全屏模式

我提出了这个想法,他喜欢它,我们一起尝试了它。我分析了WebDriver的模拟究竟是如何完成的,并模拟了我的解决方案以在此基础上编写测试。令我惊讶的是,它完美无缺。

现在 web 驱动程序被模拟了,只需要编写实际测试来测试我正在测试的两个函数的所有分支案例。一旦一切都设置好了,只需将函数的返回标志声明为每个分支实际返回的内容。除了基本的字符串断言之外,它实际上并没有太多的东西。完成后,我进行了 PR。

感觉不错,伙计。我还没有检查 PR 是否被接受;我的 Java 一点也不好,所以希望没有问题,我做的一切都是正确的。

[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--B9I5-vK---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https:// /dev-to-uploads.s3.amazonaws.com/i/poert7fr8ur4j759d4es.png)

总的来说,从我使用 Python 和 JavaScript 完成的小测试来看,我发现 JavaScript 上的 Jest 测试库更直观、更易于使用,这并不是说我完全讨厌pytest。这是一个很好的库,可以做我想做的一切,只是没有 Jest 为我做的那种感觉。我无法解释。这来自一个不太喜欢 JS 的人。也许有一天我会有更多的经验来形成一个实际的意见。

我一直想在我的代码中采用一种TDD编写代码的方法——尽管我不得不说这个实验室让我终于明白了为什么大多数开发人员并不真正关心编写测试。它很复杂,很麻烦,而且常常很笨重,而且感觉像是一件苦差事。我确实认为这是一个必要的邪恶,所以我认为最好在任何项目中尽早采用这种方法。我期待更多地了解它,并为下学期的顶点项目编写一些测试,这无疑会惹恼我的小组成员。

真的很喜欢这个实验室,我期待下一个。

与学校教育无关,我最近在 twitter 上联系了一位开发人员,询问我如何参与大型仿真项目。我的 C++ 不是很好,任何比这更低的水平......嗯,不存在。就像我的数学背景一样。如果有人好奇,我将在这里为我发布他的建议:

我唯一的建议是永远不要停止好奇。

这听起来像是一个超级预设的回应,但实际上,我之所以参与仿真,是因为我对系统的工作原理非常好奇,并想尝试让事情变得更好。

当我开始从事 Dolphin 工作时,我基本上没有 C++ 的经验,我只真正了解 Java 和 C#。当你开始享受工作的乐趣时,你是否知道某事并不是真正值得担心的事情;当您尝试为项目做出贡献时,您将随着时间的推移获得这些知识。

你可以尝试阅读世界上所有的 C++ 文章和书籍,我相信你也会从中学到东西,但是如果没有任何东西来推动学习这些材料,这将是一个让你筋疲力尽的好方法。

在为 Dolphin、citra 或 yuzu 等项目做出贡献时,您无需了解世界上有关模拟器或系统的所有知识即可开始贡献。所需要的只是“哦,关于这个软件的 [thing] 可能可以通过做 [x] 来改进”,我想。

好人。或者gal,有一些很好的建议。也许有一天我们可以喝一杯,那会很有趣。

我最近还发现了用rainy mood+lofi hip hop radio编程的奇妙之处。强烈推荐它搭配一瓶酒和一支蜡烛,这样你就可以感受到_bourgeois_(在你的内衣里写下糟糕的代码,因为没有人再离开他们的房子了)。

最后,Typora 写这些博客真是太棒了。我想我可能只是从 Evernote 迁移到这个,因为随着时间的流逝,Evernote 不知何故变得越来越糟。也强烈推荐它。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3