Повышение достоверности теста при снижении затрат

Писать тесты сложно. 😤
Зачем они вообще нужны? 🤔

Код определяет набор инструкций для выполнения определенной операции. Считайте, что эта функция выполняет четко определенную математическую операцию:
y = a + b.
Предполагая, что разработчик понимает основные принципы, он может написать эту правильную реализацию в машинном коде:

//seems about right
function Add(a,b) {
 return a + b;
}

Однако шум из-за человеческой ошибки, системных ограничений или других ошибок может повредить код:

function Add(a,b){
 return a + ‘ ’ + b; //woops!
}

Вот тут-то и нужны тесты. ✨

Тесты описывают операцию на языке «поведение-результат»,
копируя машинный язык кода.
Поврежденный код будет отражаться как сбои теста:

import Add;
test(‘add should return the sum of two numbers’, () => {
  expect(add(2,3)).toBe(5); //error! it is actually ‘2 3’!
});

Повышение достоверности при снижении затрат

Математически «обычный» код - это непрерывная функция, а тесты - это дискретные образцы одной и той же операции. Создание и поддержание размера выборки, достаточного для обеспечения правильности, может быть столь же сложной задачей, как и написание самого «обычного» кода. 😞

Так почему бы не использовать существующие тесты повторно, как мы это делаем с нашим «обычным» кодом? 😃

Повторное использование тестов

Я знаю, что повторное использование тестов - ужасный опыт.
Разрабатывать существующий бесконечный переплетенный код достаточно сложно, независимо от того, насколько хорошо он написан.
Если вы когда-нибудь осмеливались переплетать тесты, держу пари, у вас есть головная боль довольно быстро.

Но я могу представить хотя бы один вариант использования, в котором это применимо:

interface IFileSystem {
  writeFile(path, content);
  unlink(path)
  …
}
//common file-system implementation:
class NodeFs implements IFileSystem {
  …
}

Большинство тестов, написанных для NodeFS, можно с небольшой адаптацией написать для IFileSystem! 😯

Другая файловая система могла бы иметь другую реализацию и при этом использовать те же тесты!

// memory-filesystem
//———————————————
// in memory file system for fast short and isolated uses.
class NodeFs implements IFileSystem {
 …
}
//memory-filesystem.test
//———————————————
import FileSystemTests
import MemFs
FileSystemTests.validate(MemFs);

Сможем ли мы сделать это сегодня?

Да! 🥳
Стоимость изоляции кода падает, и даже тесты стоят затраченных усилий.

Одним из самых интересных инструментов в области изоляции кода является Bit (Github). Bit - это инструмент и платформа, которые помогают изолировать код. Bit также предлагает быстрый и простой способ поделиться вашими изолированными компонентами с коллекцией в bit.dev, чтобы другие (и ваше будущее) могли использовать их и даже сотрудничать. Бит обычно используется для компонентов пользовательского интерфейса как способ постепенного создания библиотеки компонентов пользовательского интерфейса, но его можно легко использовать для служебных функций и тестов Node / JS.



  1. Напишите свой тест:
import expect from ’chai’; //you gotta get it somewhere
import { IBinaryOperation } from ’math-functions’;
import { toPairs } from ’combinatorics’;
function validateAssociativity<T>(
  operation: IBinaryOperation<T>,
  values: T[]) {
  toPairs(values).forEach((x, y) => {
      expect(binaryOperation(x, y))
    .toEqual(binaryOperation(y, x));
  }
}
export validateAssociativity;

2. Разделите тест на атомарный компонент с помощью Bit:

§ bit add AssociativeTests.Ts —-id math/tests/associativity
§ bit add -c bit.envs/compilers/typescript
§ bit tag math/tests/associativity

3. Вставьте компонент в свою коллекцию в bit.dev:
(узнайте, как создать свою коллекцию Bit здесь)

§ bit export collection.name math/tests/associativity

3. Теперь мы можем легко повторно использовать наш общий многоразовый тестовый компонент:

import add from ’./add.js’;
import { validateAssociativity } from ’@bit/collection.name.math.tests.associativity’;
test(‘add associativity’, () => {
const sample = [1, 5, 3, 1000, 0.3, -17];
  // or maybe.. math/samples/realNumbers ..?
validateAssociativity(add, sample);
}

Довольно аккуратно! 🤯

Будут ли компоненты pngSnapshot следующей популярной вещью? 🔮
Могли бы мы иметь контрольные списки, такие как поддержка специальных возможностей, квота FPS и отзывчивость экрана?
Как вы думаете? 😍

Учить больше