Why I use Tape Instead of Mocha & So Should You

Why I use Tape Instead of Mocha & So Should You

为什么我要使用 Tape 来替代 Mocha & 你也应该这么评估软件质量

作者Eric Elliott

写作时间:Jul 13, 2015

TL;DR: Mocha is a $150k Porsche Panamera when the best tool for the job is a $30k Tesla Model 3. Don’t waste your resources on testing bells and whistles. Invest them in creating your app, instead. >总结: Mocha 是一个价值 150 刀的保时捷,但是往往我们工作中只需要 30 刀的特斯拉就能带来最好的效益。不要为了使用一个测试软件而去使用测试软件,而是使用他们来驱动你的程序开发。
UPDATE: I have written a simplified wrapper around Tape to make it even simpler to write great unit tests which provide clear bug reports when they fail. See “Rethinking Unit Test Assertions” for more details.
UPDATE:我对 Tape 进行了简易封装,使它能够更容易的编写出优秀的单元测试,且能够在测试用例未通过时提供清晰的错误报告,有关其更多信息请参考 “Rethinking Unit Test Assertions”

Sometimes popularity is an indication of quality. Other times, popular things are popular for popularity’s sake, and not because they’re better than alternatives.

一般而言,受欢迎程度反映了事物的质量。但有时,受欢迎的事物只是因为受欢迎而受欢迎,而不是因为它们比非主流的更好。

On real production projects, I have used Jasmine, Mocha, NodeUnit, Tape, and a bunch of other solutions. I have investigated many other options. For the last few years, I have used and continue to use Tape along with Supertest (for API testing) on all of my personal projects and projects that I lead.

在实际的生产项目中,我曾使用过 Jasmine,Mocha,NodeUnit,Tape 和许多其他解决方案。我研究过各种框架。但是在过去的几年中,我在我所有的个人项目和我主导的项目中都使用并继续使用Tape和 Supertest(用于 API 测试)。

What are Unit tests?

什么是单元测试?

Unit tests exist to test individual units of software functionality. A unit is a module, component, or function. They’re bits of the program that can work independently of the rest of the program. The presence of unit testing implies that the software is designed in a modular fashion. You may hear once in a while that there are ways to make software “more testable.”

单元测试常见于测试软件功能的各个单元。单元是可以是一个模块,组件或函数。它们是程序的一部分,可以独立于程序的其余部分工作。单元测试的存在意味着该软件是以模块化方式设计的。您可能偶尔会听到有一些使软件“更具可测试性”的方法。

If you find that it’s hard to write unit tests for your program without mocking lots of other things, that’s a sign that your program is not modular enough. Revealing tight coupling (the opposite of modularity) is one of the many important roles that unit tests play in software creation.

如果您发现很难在不模拟许多其他事情的情况下为程序编写单元测试,则表明您的程序不够模块化。发现耦合(与模块化相反)是单元测试在软件开发中扮演的许多重要功能之一。

Every module should have unit tests, and every application should be made up of modules. In other words, if you’re not writing unit tests, you should be.

每个模块都应该有单元测试,每个应用程序都应该由模块组成。换句话说,如果您不编写单元测试,则更应该这么做。

What’s Wrong with Mocha, Jasmine, etc…?

Mocha,Jasmine 等框架都存在什么问题?

  1. Too much configuration : Choose an assertion library, chose a reporting library, chose a task runner (Grunt, Gulp, etc…) Then figure out how to translate the documentation examples to the reporting library / task runner you chose. All of this is too much cognitive load. Vs: Choose Tape. Done.

  2. **Globals: **Mocha, Jasmine, and several other alternatives pollute the global environment with functions like describe, it, etc… Some assertion libraries extend built-in prototypes. Aside from removing the self-documenting nature of simple module exports, those decisions could potentially conflict with the code you’re trying to test. Vs: Tape’s simple module export.

  3. Shared State: Functions like beforeEach and afterEach actively encourage you to do something you definitely should not do: Share state between tests. Vs. Tape: No such functions for global state sharing. Instead, call setup and teardown routines from individual tests, and *contain all state to local test variables.*

  4. 过多的配置项:选择一个断言库,选择一个报告库,选择一个任务组织器 (Grunt, Gulp, etc…),然后还得学习你所选择的报告库和任务组织器的文档示例,学习成本过高。相比之下:选择使用 Tape,完事~

  5. 全局变量:Mocha,Jasmine 等等通过describeit等全局函数污染全局环境。某些断言库扩展了内置原型。除了破坏了模块的纯净性以外,这些操作还可能与您要测试的代码冲突。相比下:Tape 的纯净模块导出。

  6. 共享状态:诸如*beforeEachafterEach之类的功能*积极地鼓励您做一些您绝对不应该做的事情:在测试之间共享状态。相比下: Tape 没有用于全局状态共享的此类功能。取而代之的是,从制定的测试用例中调用挂载和卸载,并将所有状态包含在本地测试变量中。

Why Tape?

为什么选择 Tape?

Mocha does way too much and gives developers way too many assertion choices, and that leads to analysis paralysis and lost productivity. Every time I have seen Mocha used on a project, I’ve seen developers dump way too much time in the testing framework and testing environment.

Mocha 给了开发者太多的断言库选择,这导致分析瘫痪和降低了生产效率。每当 Mocha 在项目中使用时,我都看到开发人员搭建在测试框架和测试环境过程中浪费了太多时间。

While I’m ranting I would be remiss if I didn’t mention that if you spend a lot of time on mocks and stubs, that’s a strong code-smell. You can probably dramatically simplify both your tests and your application by breaking your app into more modular chunks.

我很想告诉你,如果您在 mocks 和 stubs 上花费大量时间,那说明你跑偏了,这是一种很糟糕的事情。因为往往将应用程序划分为更多的模块,您就能过极大地简化测试和应用程序。

Mocking is a code smell.

过重的 Mock 是一中糟糕的编码习惯

A few simple mocks here and there are OK. Some of your app will inevitably involve side-effects (reading from or writing to the network or filesystem, for instance). When you do have a genuine need for mocks, keep them simple. Little more than basic stubs are ideal. But on many projects, I’ve seen a lot of over-complicated mocks that never needed to exist in the first place. Why maintain more code than you need to?
The more you break your problems down into simple, pure functions, the easier it will be to test your code without mocks.
一些简单的 Mocking 可以接受。部分情况下,您的某些应用程序不可避免地会被带入副作用(例如,从网络或文件系统读取或写入网络或文件系统)。当您确实需要 Mock 时,请尽量使其简单。采用更多基础 stubs 是不错的主意。但是在许多项目中,我看到了很多过于复杂的 Mock,这些 Mock 从一开始就不需要存在。为什么要维护比您所需更多的代码?
将问题分解成简单的 函数的次数越多,_无需 Mock 就可以测试代码_。

Testing is not what you should spend most of your time doing.

你不应该投入大量时间去编写测试用例

You should spend most of your time thinking about how to create the best, most flexible, most performant solutions given the afforded time constraints. Time is value in the software development world, and you shouldn’t waste one minute of it.

在有限时间的开发周期内下,您应将大部分时间都花在如何创建更好,更灵活,更高性能的解决方案上。在软件开发世界中,时间很重要,您不应该浪费时间。

If you get your kicks burning money, use Mocha, Jasmine, Jest, etc… But if you value your time, keep reading.

如果并无所谓,可以使用 Mocha,Jasmine,Jest 等。但是,如果您珍惜你的时间,请继续阅读。

With many BDD assertion libraries, there are getters with side effects. At one company I worked for (not naming names), that buried a bug in one of our tests, and we spent far too long debugging the test case rather than developing actual application code.

在许多 BDD 断言库中,他们都有些带有副作用的 getters。在我工作的一家公司(没有命名),这在我们的一个测试中掩埋了一个错误,并且我们花了太多的时间调试测试用例,而不是开发实际的应用程序代码。

Test assertions should be dead simple,& completely free of magic.

测试断言应该尽可能的简单,并且完全没有黑魔法(不带入除应有实现的实现)

equal, deepEqual, pass & fail are my primary go-to assertions. If equal and deepEqual were the only assertions available anywhere, the testing world would probably be better off for it.

Why? equal & deepEqual provide quality information about expectations, and they lead to very concise test cases that are easy to read & maintain.

When you write a bug report, you should always provide a description, explain what you expected to see, and explain what you actually saw.

Test cases should be written in much the same way:

  1. Describe the feature that you’re testing in plain English.
  2. Provide the expected outcome of the test. This part is why many unit tests are called expectations.
  3. Compare that to the actual value.

When a unit tests fails, the error message is your bug report.

equal, deepEqual, pass & fail 是我常用的断言。如果*equal* and deepEqual 是唯一可用的断言,那么测试可读性会变得更好。

为什么?_equal_ & deepEqual 提供有关期望的质量信息,它们测试用例使非常简洁,易于阅读和维护。

编写错误报告时,应始终提供说明,解释您期望看到的内容,并解释您实际看到的内容

测试用例的编写方式一般参见如下:

  1. 用简单的英语描述您要测试的功能。
  2. 提供测试的预期结果。这就是为什么许多单元测试称为期望的原因。
  3. 将其与实际值进行比较

当单元测试失败时,错误消息就是您的错误报告。

Your test descriptions should be clear enough to use as documentation.

您的测试描述应足够清晰,以至可以当作文档阅读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import test from 'tape'

test('A passing test', (assert) => {
assert.pass('This test will pass.')

assert.end()
})

test('Assertions with tape.', (assert) => {
const expected = 'something to test'
const actual = 'sonething to test'

assert.equal(
actual,
expected,
'Given two mismatched values, .equal() should produce a nice bug report'
)

assert.end()
})

If you write tests this way, your test error messages should be clear enough to use as bug reports:

如果你这么写测试用例,则你的测试错误信息将会足够清楚,甚至用来当作 bug 报告来看。

1
2
3
4
5
6
7
8
9
10
11
12
13
TAP version 13
# A passing test
ok 1 This test will pass.
# Assertions with tape.
not ok 2 Given two mismatched values, .equal() should produce a nice bug report
---
operator: equal
expected: 'something to test'
actual: 'sonething to test'
...1..2
# tests 2
# pass 1
# fail 1

Your automated test error messages are your bug reports.

您的自动测试错误消息就是您的错误报告。

Simple tests assertions provide:

  • Better readability.
  • Less code.
  • Less maintenance.

These features trump all the bells and whistles in the world.

Author: liuarui
Link: https://liuarui.github.io/2021/02/01/单元测试/Why I use Tape Instead of Mocha & So Should You/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.