Я принял решение Стюарта Уотта и побежал с ним (и немного увлекся). Решение Стюарта хорошее, но мне было неловко думать, что генератор случайных чисел всегда выплевывает 0,5 - кажется, что бывают ситуации, когда вы рассчитываете на некоторую дисперсию. Я также хотел высмеять crypto.randomBytes
для моих паролей солей (используя сервер Jest). Я потратил немного времени на это, поэтому решил, что поделюсь знаниями.
Одна из вещей, которые я заметил, это то, что даже если у вас есть повторяемый поток чисел, введение нового вызова в Math.random()
может испортить все последующие вызовы. Я нашел способ обойти эту проблему. Этот подход должен применяться практически ко всем случайным вещам, которые вам нужно высмеять.
(примечание стороны: если вы хотите, чтобы украсть это, вам нужно установить Chance.js - yarn/npm add/install chance
)
издеваться Math.random
, поставить это в один из файлов, указанных в вашем package.json
«ы {"jest":{"setupFiles"}
массива:
const Chance = require('chance')
const chances = {}
const mockMath = Object.create(Math)
mockMath.random = (seed = 42) => {
chances[seed] = chances[seed] || new Chance(seed)
const chance = chances[seed]
return chance.random()
}
global.Math = mockMath
Вы заметите, что Math.random()
теперь имеет параметр - семя. Это семя может быть строкой. Это означает, что, когда вы пишете свой код, вы можете вызвать генератор случайных чисел, который вы хотите по имени. Когда я добавил тест на код, чтобы проверить, сработало ли это, я не использовал его. Это привнесло мои ранее издевавшиеся снимки Math.random()
. Но затем, когда я изменил его на Math.random('mathTest')
, он создал новый генератор под названием «mathTest» и остановил перехват последовательности из стандартной.
Я также высмеивал crypto.randomBytes
для моего пароля соли. Поэтому, когда я пишу код для создания моих солей, я могу написать crypto.randomBytes(32, 'user sign up salt').toString('base64')
. Таким образом, я могу быть уверен, что никакой последующий вызов crypto.randomBytes
не испортит мою последовательность.
Если кто-либо еще интересуется насмешкой crypto
таким образом, вот как. Поместите этот код в <rootDir>/__mocks__/crypto.js
:
const crypto = require.requireActual('crypto')
const Chance = require('chance')
const chances = {}
const mockCrypto = Object.create(crypto)
mockCrypto.randomBytes = (size, seed = 42, callback) => {
if (typeof seed === 'function') {
callback = seed
seed = 42
}
chances[seed] = chances[seed] || new Chance(seed)
const chance = chances[seed]
const randomByteArray = chance.n(chance.natural, size, { max: 255 })
const buffer = Buffer.from(randomByteArray)
if (typeof callback === 'function') {
callback(null, buffer)
}
return buffer
}
module.exports = mockCrypto
А потом просто позвонить jest.mock('crypto')
(опять же, я его в одном из моих «SetupFiles»). Поскольку я выпускаю его, я пошел вперед и сделал его совместимым с методом обратного вызова (хотя я не собираюсь использовать его таким образом).
Этих два фрагмент кода пройти все 17 из these tests (я создал __clearChances__
функций для beforeEach()
с - это просто удаляет все ключи от chances
хэша)
Update: Использую это в течение нескольких дней, и теперь Я думаю, это работает очень хорошо. Единственное, я думаю, что, возможно, лучшей стратегией будет создание Math.useSeed
функции, запущенного в верхней части тестов, которые требуют Math.random
Как вы думаете, «тест ... этот выход случайный» означает даже? Переверните монету, и вы можете получить головы дважды подряд; если это невозможно, это не случайно. Пункт «случайный» - это * вы не знаете, какое значение вы ищете *. На практике вы можете запустить функцию дважды для одного входа и ожидать разные выходы, но некоторые (очень низкие) проценты времени, которые он должен выполнить, даже с рабочим кодом. –
Конечно, тестовая случайность - это глупость. Я спрашиваю, как ** проверить ** такие случаи в принципе. Я просто не знаю, как это сделать. –
Ключ здесь, а не случайность. Может быть, случайная часть должна быть ограничена или так. Я тестирую noob, поэтому задаюсь вопросом. –