测试不适合初学者
我非常喜欢测试。我在博客上写测试相关的文章,给我的邮件列表发送测试相关的邮件,在空闲时间与其他开发者讨论测试,我甚至还创建了一门用 Go 语言教授测试的课程。
虽然我很喜欢测试,但我并不建议初学者这样做。
是不是很不可思议?在本文中,我将更详细地探讨其中的原因,但基本上可以归结为两点:
- 初学者知识储备不足,只能编写最简单的测试用例。这自然引出了我的第二点……
- 既要学习编写实际测试所需的技能,又要学习如何编程和构建东西,这让人感到不知所措。
我觉得这算是一点吧。算了。我把它分成两部分,因为我觉得这样更容易理解。
我知道你们很多人可能现在并不认同我的观点,但请认真阅读这篇文章。如果读完后你们仍然不同意,我很乐意与你们讨论。毕竟,我也是来学习的🙃
本文最初发表于calhoun.io,我在该网站上撰写有关 Go、Web 开发、测试等方面的文章。
初学者知识不足,只能编写最简单的测试用例。
对于初学者来说,编写代码的首要目标并非分离关注点、避免使用全局变量或编写可测试的代码。说实话,大多数初学者可能根本不知道这些概念的真正含义。相反,他们的首要目标很简单:就是让程序运行起来。仅此而已。
验证这一点几乎毫不费力。花点时间看看一些初学者写的代码就知道了。
如果你正在查看一个用 Go 语言编写的 Web 应用程序,那么他们很可能在代码的任何地方都编写了 SQL 查询,而且他们的数据库连接很可能是一个全局变量。
正在查看 Rails 应用?很可能视图中包含业务逻辑,而控制器中则塞满了大量的逻辑。
如果你正在查看一个 PHP Web 应用程序,那么如果所有逻辑都放在一个 PHP 文件中——解析表单、与数据库交互等等——我一点也不会感到惊讶。
即使我们来看一些更简单的东西——比如功能有限的计算器——仍然会遇到类似的问题。这并不是说初学者不在乎;而是他们缺乏相关知识。
初学者不知道什么是依赖注入,也不理解全局变量如何使测试变得困难。他们可能甚至不知道什么是模拟(mocking),所以指望他们理解如何设计易于模拟的代码是不现实的。
因此,对于初学者来说,真正有意义的测试只有像下面这样非常简单的测试。
func Add(a, b int) int {
return a+b
}
// And a test...
func TestAdd(t *testing.T) {
got := Add(2, 4)
want := 6
if got != want {
t.Errorf("Add() = %d; want %d", got, want)
}
}
虽然我不介意向初学者展示这段代码,让他们了解什么是测试,但我认为向他们展示这段代码并假装它像一个真正的测试是非常荒谬的。
所以最终的结果就是,我们试图教他们更多东西。我们试图教他们什么是依赖注入,为什么全局变量会使测试变得困难,如何time.Now()使验证边界情况变得困难等等。而这正是我开始担心的地方,因为我们不再是在教初学者如何编程了。此时,我们是在同时教他们如何编程、如何构建东西以及如何测试。这就引出了我的第二点……
既要学习编写实际测试所需的技能,又要学习编程和构建项目,这简直让人不堪重负。
和之前一样,我希望你们思考一下初学者编写的代码,但这次我希望你们回忆一下自己最早编写的一些程序。想想你做的第一个由多个源文件组成的程序。或者想想你做的第一个网页。
如果你和我一样,你的第一个网页应用可能看起来像这样:
<p>
<?php
// This may not work. I don't know PHP anymore.
$name = $_GET['name'];
echo "Hello, " . $name;
?>
</p>
一件艺术品,不是吗?
现在想象一下,如果你刚刚写完这段代码,就有人告诉你应该测试代码,应该使用 React,应该使用框架,哦,对了,你还得搭建数据库,可能还要搭建 GraphQL 来查询。
我也不知道为什么,但作为开发者,我们总有这种习惯:把我们多年经验积累下来的技能,期望其他人,尤其是新手,能立刻做到。这简直荒谬。这就好比我们学过三角函数、代数等等,最终也用微积分解决过某个问题,却期望别人能立刻掌握微积分一样。
仅仅因为某种方法对你有效,并不意味着它对初学者也适用。他们可能缺乏必要的背景知识、经验或练习,无法真正从你使用的方法中获益。或者,他们要解决的问题可能要简单得多,引入所有这些复杂性反而会适得其反。
我们似乎都忘记了,我们曾经一步步学习过HTTP请求的工作原理,HTTP请求头的工作原理,Cookie的工作原理,表单的工作原理,以及如何向Web服务器发送POST请求——甚至忘记了HTTP还有其他不同的请求方法。而这一切,我们很可能都是通过反复试验才学会的。
我并不认为测试本身有问题,真正的问题在于我们有一种根深蒂固的观念,认为你应该同时学习编程、测试、Web开发以及其他数不清的东西。我不太清楚这种观念是如何形成的,但我怀疑部分原因在于我们从未对这些知识进行过明确的界定。当一个初学者问“我应该学什么?”时,我们会告诉他们“学习测试、React、GraphQL和Go,但只能使用标准库……”
不,不,不!住手!
我觉得这很荒谬,因为在其他任何情况下这都是显而易见的。如果你教别人踢足球,你会从传球和运球等基本技巧开始。你不会一开始就给他们看罗纳尔多的视频,然后说“职业球员就是这么做的”。那么,我们为什么要对编程初学者这样做呢?
我们试图安慰他们说:“他们当然应该知道不能一口气学完所有东西”,但他们就是不明白!更糟糕的是,当那些初出茅庐的开发者掉进这个陷阱时,一旦遇到困难,他们就会感到无比沮丧。他们会觉得自己根本不具备成为开发者的潜质,这实在令人惋惜,因为如果不是碰壁,他们中的许多人都会热爱编程。
这就引出了我的真正观点——我们大多数人如果一次只专注于学习几样东西,学习效果会更好。我们渴望挑战,渴望尝试新事物,但我们不想被过多的知识压垮,以至于无法继续学习。试图同时学习测试以及其他所有知识——比如如何构建Web应用程序、HTTP的工作原理、Cookie的工作原理等等——很容易让人感到不知所措。因此,我通常建议先学习其他知识,然后再回头学习测试。你可以随时回顾之前的项目,看看如何重新设计并应用你正在学习的测试知识,但这只有在你不感到不知所措、不感到沮丧、最终放弃的情况下才有可能实现。
但是如果我想学习测试呢?!(以及其他数不清的“如果”)。
好啊,那就去学吧!完全可以先学测试,然后再学 Web 开发或其他任何主题。我相信很多人都这么做过,你或许也会喜欢。我说测试不适合初学者,并不是说它不好学。我的意思是,试图同时学习测试和其他所有东西是个错误。
大多数人想先学习如何构建 Web 应用或其他可视化工具,但这并不意味着你必须从那里入手。你完全可以先学习测试。有些内容可能不经实践就难以理解,但无论如何,我绝不想阻止你学习自己想学的东西。
这并不意味着你不能在结对编程或其他类似环境中学习。在有导师的环境下,即使感到压力巨大,你通常也能学到很多东西,因为有人会指导你。当你迷茫时,你不会束手无策,也不会觉得自己失败了。有人会告诉你:“你做得很好,只是信息量有点大。下次试试 X 和 Y!” 简而言之,在这种情况下,感到压力过大、遇到困难最终放弃的情况并不那么令人担忧。
嘘……
对学习或练习 Go 语言感兴趣吗?来看看我的免费课程——Gophercises——面向 Go 语言初学者的编程练习。
我还有一些高级课程,涵盖Go 语言 Web 开发和Go 语言测试,您也可以了解一下。
文章来源:https://dev.to/joncalhoun/when-nil-isnt-equal-to-nil-5bbh
