Comments 13
Я подразумевал живых людей из дельта окрестности. Библиотек то – на любой вкус.
И jest `мокает` так же как sinon. Это не перехват внутренней зависимости модуля, а внешней.
Представим что вас есть код на реакте
 const someComponent = ()....

 const mapStateToProps = (state) => ({
   awesomeData: coolSelectorFromReduxStore
 });

 const ConnectedComponent = connect(connect(
  mapStateToProps
)(someComponent);

И вы тестируете именно ConnectedComponent. Ну бывает.
Стандартные средства заставят вас собрать правильный store, обернуть все в Provider и все будет плохо. Там нечего мокать «напрямую». Все спрятано в файле и в тесты не светит.

Rewiremock и компания же могут «по живому» перегрузить connect или coolSelectorFromReduxStore внутри файла, а не снаружи, и итоговый тест будет прост как три копейки.
Как будет выглядеть подобный пример, если заменить proxyquire на rewiremock?
// test.js
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const assert = require('assert');

const uptime = sinon.spy();

proxyquire('./app', { process: { uptime } });

const app = require('./app');
assert(uptime.notCalled);
app.uptime();
assert(uptime.calledOnce);

// app.js
const process = require('process');
module.exports = {
    uptime: process.uptime,
};
У вас не совсем корректный пример. Точнее вы не правильно используете proxyquire.
Ваш пример работает на основе паразитного сайд эффекта работы библиотеки, а точнее на основе странного поведения, когда после работы proxyquire в кеше модульной системы остается мокнутая версия process.
Буквально в следущем тесте, когда вы уже будете ожидать «нормальное» поведение — вам прилетит сюрприз.
Не делайте так. Очень много людей ночами не спали, все думали почему по одиночке их тесты работают, а все вместе — падают.
Правильный код:
const app = proxyquire.noPreserveCache().load('./app', { process: { uptime } }); // app с мокнутым process
const app = require('./app'); // "настоящий" app, как и должно быть

PS: В любом случае «нужный» app надо забирать из метода load, а не require. Даже если noPreserveCache вам не нужен.

В то же время такой код нормален для rewiremock
rewiremock('process').with({uptime});

rewiremock.enable();
const app = require('./app'); // app с мокнутым process
rewiremock.disable(); // вычистит все затронутые модули

const app = require('./app'); // "настоящий" app, как и должно быть
Спасибо за доходчивое разъяснение. Насчет странного поведения, мне оно казалось вполне ожидаемым, точнее то что proxyquire заменяет кешированную версию модуля и если бы нужно было вернуть нормальное поведение я бы удалил модуль из кеша в соответствии с документацией https://nodejs.org/api/globals.html#globals_require_cache. Ваш вариант rewiremock с enable/disable действительно выглядит намного лучше и понятнее.
В readme репозитория не помешал бы список публичных методов API с их кратким описанием, а в репозитории папка examples с простыми и самодостаточными примерами без лишнего кода. В остальном rewiremock выглядит приятно, возьму на вооружение.

Я так понимаю вот это мораль истории:


У нормальных людей — нормальный DI.

Но когда не до этого, то rewiremock может выручить. Правильно?

Все верно —
От каждого по способностям, каждому по потребностям.

Если нет способностей, но есть потребности — rewiremock и аналоги помогут.

Отправил вам PR. А как rewiremock будет работать с паралельными тестами (как в jest/ava)? Если я правильно понимаю то так же как и другие, т.е. лучше так не делать.

Жил в России — все фигели от моего русского. Переехал зарубеж — теперь все фигеют от моего английского.

Насчет параллельных тестов — сразу честно — не тестировал, но должно работать. Потому что:
1. База моков — общая (надо будет сделать простой интерфейс по клонированию и ресету моков перед началом теста).
2. По enable/disable из кеша вырезаются все мокнутые файлы и все файлы что как либо от них зависят.
Итого можно быть увереным, что после enable получите ровно то, что и нужно, а после disable — все вернется на круги своя.

Единственная проблема — ресет.
Возможно вот такой код сработает:
//mocks.js
 rewireMock('file1'); // do nothing, just indicate mock, to wipe it from a cache
 rewireMock('file2');


//test.js
 rewireMock('file1').with(something); // override mock.
PS: Проблемы с общими моками, подключенными через третий файл — нет. У каждой инстанс сам за себя, так как rewiremock сам себя из кеша вырезает. Общий только кеш nodejs.
Only those users with full accounts are able to leave comments. Log in, please.