snion中文文档 Fakes

Fakes

介绍

  • fake从 v5 版本开始可在 Sinon 中使用。
  • fake 拥有创建具有设置默认行为fake Function 功能。
  • 使用具有与sinon.stub中相同的 API 的Functions来设/Users/lm/Desktop/note/snion 中文文档/Fakes.md 置行为
  • 创建的具有或不具有行为的fake Function具有与(sinon.spy)spies相同的 API。

Sinon 中,fake 是一个 Function 它记录其所有调用的参数,返回值,this 的值和引发的异常(如果有)。
fake是不变的:一旦创建,行为就不会改变。

sinon.spysinon.stub 方法不同,sinon.fakeAPI 仅关注如何创建 fake,而与将fake插入被测系统无关。
要将fake插入被测系统,可以使用这些 sinon.replace\*方法。

创建一个 fake

创建一个有或没有行为的fake Function, 创建的函数都将具有与 sinon.spy 相同的 API。

  • Creating a fake without behavior
1
2
3
4
5
6
7
8
// create a basic fake, with no behavior
var fake = sinon.fake()

fake()
// undefined

fake.callCount
// 1
  • Creating a fake with custom behaviour
1
2
3
4
5
// create a fake that returns the text "foo"
var fake = sinon.fake.returns('foo')

fake()
// foo

Fakes 的行为

行为一旦创造,就无法改变。

sinon.fake.returns(value);

创建返回值参数的 fake。

1
2
3
4
var fake = sinon.fake.returns('apple pie')

fake()
// apple pie

sinon.fake.throws(value);

创建一个 fake,该 fake 将使用提供的值作为 message 属性抛出 Error。

如果将 Error 作为 value 参数传递,则将作为抛出的值。 如果传递了任何其他值,则该值将用于引发 Error 的 message 属性。

1
2
3
4
var fake = sinon.fake.throws(new Error('not apple pie'))

fake()
// Error: not apple pie

sinon.fake.resolves(value);

Creates a fake that returns a resolved Promise for the passed value.

sinon.fake.rejects(value);

Creates a fake that returns a rejected Promise for the passed value.
如果错误被作为值参数传递,那么这将是 promise 的价值。
如果传递了其他任何值,则该值将用于 promise 返回的 Error 的 message 属性。

sinon.fake.yields([value1, …, valueN]);

sinon.fake.yields takes some values, and returns a function that when being called, expects the last argument to be a callback and invokes that callback with the same previously given values. The returned function is normally used to fake a service function that takes a callback as the last argument.

In code example below, the ‘readFile’ function of the ‘fs’ module is replaced with a fake function created by sinon.fake.yields. When the fake function is called, it always calls the last argument it received, which is expected to be a callback, with the values that the yields function previously took.

1
2
3
4
5
6
7
8
var fake = sinon.fake.yields(null, 'file content')
sinon.replace(fs, 'readFile', fake)
fs.readFile('somefile', (err, data) => {
console.log(data)
})
console.log('end of this event loop')
// file content
// end of this event loop

sinon.fake.yieldsAsync([value1, …, valueN]);

Similar to yields, yieldsAsync also returns a function that when invoked, the function expects the last argument to be a callback and invokes that callback with the same previously given values. However, the returned function invokes that callback asynchronously rather than immediately, i.e. in the next event loop.

Compare the output of the code example below with the output of the code example above for yields to see the difference.

1
2
3
4
5
6
7
8
var fakeAsync = sinon.fake.yieldsAsync(null, 'file content')
sinon.replace(fs, 'readFile', fakeAsync)
fs.readFile('somefile', (err, data) => {
console.log(data)
})
console.log('end of this event loop')
// end of this event loop
// file content

sinon.fake(func);

Wraps an existing Function to record all interactions, while leaving it up to the func to provide the behavior.

The created fake Function has the same API as a sinon.spy.

This is useful when complex behavior not covered by the sinon.fake.* methods is required or when wrapping an existing function or method.

Instance properties

The instance properties are the same as a sinon.spy.

f.callback

This property is a convenience to get a reference to the last callback passed in the last to the fake.

1
2
3
4
5
6
7
8
9
var f = sinon.fake()
var cb1 = function () {}
var cb2 = function () {}

f(1, 2, 3, cb1)
f(1, 2, 3, cb2)

f.callback === cb2
// true

The same convenience has been added to spy calls:

1
2
3
4
5
f.getCall(1).callback === cb2
// true
//
f.lastCall.callback === cb2
// true

f.firstArg

This property is a convenient way to get a reference to the first argument passed in the last call to the fake.

1
2
3
4
5
6
7
8
9
var f = sinon.fake()
var date1 = new Date()
var date2 = new Date()

f(date1, 1, 2)
f(date2, 1, 2)

f.firstArg === date2
// true

f.lastArg

This property is a convenient way to get a reference to the last argument passed in the last call to the fake.

1
2
3
4
5
6
7
8
9
var f = sinon.fake()
var date1 = new Date()
var date2 = new Date()

f(1, 2, date1)
f(1, 2, date2)

f.lastArg === date2
// true

The same convenience has been added to spy calls:

1
2
3
4
5
6
7
f.getCall(0).lastArg === date1
// true
f.getCall(1).lastArg === date2
// true

f.lastCall.lastArg === date2
// true

Adding the fake to the system under test

Unlike sinon.spy and sinon.stub, sinon.fake only knows about creating fakes, not about replacing properties in the system under test.

To replace a property, you can use the sinon.replace method.

1
2
3
4
5
6
var fake = sinon.fake.returns('42')

sinon.replace(console, 'log', fake)

console.log('apple pie')
// 42

When you want to restore the replaced properties, call the sinon.restore method.

1
2
// restores all replaced properties set by sinon methods (replace, spy, stub)
sinon.restore()

snion中文文档 General setup

通用配置 -Sinon.js

  • Sinon用于创建fakesspiesstubs
  • 默认情况下,它们是在默认沙箱中创建的。 因此我们需要确保在每次测试后还原沙箱。

举个例子,如果您使用的是 Mocha,则可以将还原沙箱的操作放在根目录下的测试文件中:

1
2
3
4
afterEach(() => {
// Restore the default sandbox here
sinon.restore()
})

或者在Jasmine中,您应该将其放在每个描述中:

1
2
3
4
5
6
describe('My test suite', () => {
afterEach(() => {
// Restore the default sandbox here
sinon.restore()
})
})

忘记还原沙箱会导致内存泄漏。
有关使用多个沙箱的更高级设置,请参阅沙箱


HTML标签相关
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- 重定向 -->
<!-- <meta http-equiv="refresh" content="1;url=http://www.baidu.com" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="prerender" href="https://www.tabao.com" />
<title>Document</title>
</head>

<body>
<a href="https://www.taobao.com">去淘宝</a>
</body>
</html>

meta

属性

  • contend

  • http-equiv[content-type | expires | refresh | set-cookie]

    • 把 content 属性关联到 HTTP 头部。

    • http-equiv 属性为名称/值对提供了名称。并指示服务器在发送实际的文档之前先在要传送给浏览器的 MIME 文档头部包含名称/值对。

    • 当服务器向浏览器发送文档时,会先发送许多名称/值对。虽然有些服务器会发送许多这种名称/值对,但是所有服务器都至少要发送一个:content-type:text/html。这将告诉浏览器准备接受一个 HTML 文档。

    • 使用带有 http-equiv 属性的 标签时,服务器将把名称/值对添加到发送给浏览器的内容头部。例如,添加:

1
2
<meta http-equiv="charset" content="iso-8859-1" />
<meta http-equiv="expires" content="31 Dec 2008" />
1
2
3
4
5
这样发送到浏览器的头部就应该包含:
content-type: text/html
charset:iso-8859-1
expires:31 Dec 2008
当然,只有浏览器可以接受这些附加的头部字段,并能以适当的方式使用它们时,这些字段才有意义。
  • name
    可选值
    • author
    • description
    • keywords
    • generator
    • revised
    • others
  • scheme
    定义用于翻译 content 属性值的格式。
1
<meta name="keywords" contend="关键词1,关键词2" />

script

  • async
    • 无顺序,谁先加载完成谁先执行
  • defer
    • 启动一个新线程去下载,然后在DOMContentLoaded事件执行前执行脚本
    • 多个按先后顺序

link

  • prefetch
  • prerender
  • preload

canvas

  • canvas API
  • webGL API

svg

https://developer.mozilla.org/zh-CN/docs/Web/SVG


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.


操作系统概念

操作系统

用户态

内核态

多路复用

  • 时间复用
  • 空间复用

操作系统决定何时分配资源

操作系统决定如何分配资源

计算机硬件

处理器

  • 寄存器
  • 流水线:执行指令的机制
  • 陷阱:将用户态转化为内核态,并将控制权交给操作系统
  • 多线程不是真正的并行,而是一个时刻只有一个进程在运行,但是线程的切换时间减少到纳秒数量级

存储器

  • 寄存器
  • 高速缓存
  • 主存 RAM
  • 磁盘

I/O

  • 中断
  • 中断优先级

总线

操作系统概念

进程

正在执行的一个程序

  • 子进程
  • 进程树
  • 进程间通信

地址空间

文件系统

  • 文件
  • 目录
    • 工作目录
    • 根目录

管道 pipe

一种虚文件,链接两个进程

保护

  • 9 位二进制保护码,所有者、同组者、其他人
  • rwx 位,读、写、执行

系统调用

  • POSIX 可移植操作系统接口
  • PID 进程标识符
  • fork 派生

操作系统结构

六种典型设计模式

  • 单体系统

  • 层次式系统

  • 微内核

  • 客户端-服务器模式

  • 虚拟机

  • 外核


进程与线程

进程

概念

一个正在执行的程序实例对应一个进程

创建

4 个主要事件会导致进程的创建

  • 系统初始化
  • 正在运行的程序执行创建进程的系统调用
  • 用户请求创建一个新进程
  • 一个批处理作业的初始化

终止

  • 正常退出 自愿
  • 出错退出 自愿
  • 严重错误 非自愿
  • 被其他进程杀死 非自愿

状态

  • 运行态

  • 就绪态

  • 阻塞态

  • 进程状态

  1. 进程阻塞
  2. 2、3 进程调度
  3. 进程等待时发生外部事件

实现

  • 进程表

线程


自动化测试

Test Doubles 理解

自动化测试中,我们常会使用一些经过简化的,行为与表现类似于生产环境下的对象的复制品。
引入这样的复制品能够降低构建测试用例的复杂度,允许我们独立而解耦地测试某个模块,不再担心受到系统中其他部分的影响;
这类型对象也就是所谓的 Test Double。

Fakes

  • Fake 是那些包含了生产环境下具体实现的简化版本的对象。

Stubs

  • Stub 代指那些包含了预定义好的数据并且在测试时返回给调用者的对象。
  • Stub 常被用于我们不希望返回真实数据或者造成其他副作用的场景。

command query separation

query 只是查询,无副作用,不改变状态 : Stubs
command 操作的同时会改变状态 : Mocks

Mocks

参考文章
https://segmentfault.com/a/1190000009443132 > http://xunitpatterns.com/Test%20Double.html > https://martinfowler.com/articles/mocksArentStubs.html

测试

  • 减少不必要的测试细节
  • 关注用户想要什么,就尽可能去测试什么

元编程

元编程

概念

  • 只要是与编程相关的编程就算是 meta-programming「元编程」

  • 简单解释
    比如,若编程甲可以输出 A - Z,那么写程序甲算「编程」;
    而程序乙可以生成程序甲(也许还会连带着运行它输出 A - Z),那么编写程序乙的活动,就可以算作 meta-programming,「元编程」。

  • 元编程常用来实现 DSL

    参考资料

DSL(特定领域语言)

外部 DSL

  • 通过解析器、babel 等编译工具实现特定语法 or 功能
  • 如 jsx

内部 DSL

  • 通过组合语言本身功能实现特定语法 or 功能
  • 如 jquery
  • 大部分实现方式使用级联、嵌套

JavaScript 中 DSL 实现

easy: 使用 proxy

参考资料


函数式编程

编程范式

三大类

  • 命令式 (过程式编程)
  • 声明式 (函数式编程)
  • 元编程 (面向对象编程)

参考资料

函数式编程

特点:

  • 函数是一等公民
    函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。
  • 无副作用
    函数内部与外部互动,不要产生运算以外的其他结果
    引出了纯函数概念
  • 不保存状态
    状态使用参数带入

高级玩法

TODO

高阶函数

参数为函数或返回值为函数的函数

函数柯里化

什么是函数式编程思维? - 用心阁的回答 - 知乎
参考资料: https://www.zhihu.com/question/28292740/answer/40336090


设计模式

找出程序中变化的地方,并将变化封装起来

重要的是模式的意图,而不是程序的结构

多态

同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果

把不变的抽离,可变的封装

封装

目的;将信息隐藏