函数式代码测试与规范捕获
立即解锁
发布时间: 2025-08-18 00:57:34 阅读量: 1 订阅数: 2 

### 函数式代码测试与规范捕获
#### 1. 函数式代码单元测试
在开发中,使用函数式库能带来诸多好处。对于像 `toLetterGrade` 这样的函数,我们可以为其编写单元测试,代码如下:
```javascript
QUnit.test('Compute Average Grade: toLetterGrade', function (assert) {
assert.equal(toLetterGrade(90), 'A');
assert.equal(toLetterGrade(200), 'A');
assert.equal(toLetterGrade(80), 'B');
assert.equal(toLetterGrade(89), 'B');
assert.equal(toLetterGrade(70), 'C');
assert.equal(toLetterGrade(60), 'D');
assert.equal(toLetterGrade(59), 'F');
assert.equal(toLetterGrade(-10), 'F');
});
```
由于 `toLetterGrade` 是纯函数,我们可以多次使用不同输入来测试其边界条件。并且,由于它具有引用透明性,我们可以随意调整测试用例的顺序,而不会影响测试结果。
对于函数组合器,如 `fork`,由于它们除了编排应用程序控制流中的函数调用外,不包含业务逻辑,所以不需要太多测试。以下是 `fork` 的测试代码:
```javascript
QUnit.test('Functional Combinator: fork', function (assert) {
const timesTwo = fork((x) => x + x, R.identity, R.identity);
assert.equal(timesTwo(1), 2);
assert.equal(timesTwo(2), 4);
});
```
使用函数式库、组合和组合器可以使开发和测试变得简单,但处理不纯行为时可能会变得复杂。
#### 2. 用单子隔离分离纯函数和不纯函数
大多数程序都有纯函数和不纯函数部分。在客户端 JavaScript 中,与 DOM 交互是常见的不纯操作;在服务器端,读取数据库或文件也是不纯操作。我们可以使用组合来结合纯函数和不纯函数,但这仍然会使程序不纯。我们可以使用 IO 单子等技术来提高程序的引用透明性,使程序更具声明性,更易于推理。
以 `showStudent` 函数为例,非函数式版本没有分离其不纯部分,导致测试效率低下且难以彻底测试。而函数式版本将其拆分为多个部分,通过组合和单子重新组合,大大提高了可测试性。
```javascript
const showStudent = R.compose(
map(append('#student-info')),
liftIO,
map(csv),
map(R.props(['ssn', 'firstname', 'lastname'])),
chain(findStudent),
chain(checkLengthSsn),
lift(cleanInput)
);
```
`showStudent` 函数中,`cleanInput`、`checkLengthSsn` 和 `csv` 这三个函数可以可靠地测试。以下是它们的单元测试代码:
```javascript
QUnit.test('showStudent: cleanInput', function (assert) {
const input = ['', '-44-44-', '44444', ' 4 ', ' 4-4 '];
const assertions = ['', '4444', '44444', '4', '44'];
assert.expect(input.length);
input.forEach(function (val, key) {
assert.equal(cleanInput(val), assertions[key]);
});
});
QUnit.test('showStudent: checkLengthSsn', function (assert) {
assert.ok(checkLengthSsn('444444444').isRight);
assert.ok(checkLengthSsn('').isLeft);
assert.ok(checkLengthSsn('44444444').isLeft);
assert.equal(checkLengthSsn('444444444').chain(R.length), 9);
});
QUnit.test('showStudent: csv', function (assert) {
assert.equal(csv(['']), '');
assert.equal(csv(['Alonzo']), 'Alonzo');
assert.equal(csv(['Alonzo', 'Church']), 'Alonzo,Church');
assert.equal(csv(['Alonzo', '', 'Church']), 'Alonzo,,Church,');
});
```
这些函数经过单独隔离和彻底测试后,我们可以安全地对它们进行重构,而不用担心影响其他部分。
#### 3. 模拟外部依赖
对于 `findStudent` 函数,它源于不纯的 `safeFindObject`,会查询外部对象存储以查找学生记录。我们可以使用模拟对象来处理这个函数的副作用。这里使用 QUnit 模拟插件 Sinon.JS,以下是具体操作步骤:
1. 初始化模拟上下文:
```javascript
const studentDb = DB('students');
const mockContext = sinon.mock(studentDb);
```
2. 设置测试模块和钩子函数:
```javascript
var studentStore, mockContext;
QUnit.module('CH06', {
beforeEach: function () {
studentDb = DB('students');
mockContext = sinon.mock(studentDb);
},
afterEach: function () {
mockContext.verify();
mockContext.restore();
}
}
```
0
0
复制全文
相关推荐










