Насколько я понимаю, этот пост в основном написан Джоном Пипкиным. Это было действительно хорошо и очень помогло мне, и я хотел, чтобы об этом поделился со всем миром.
Щелкните здесь, чтобы увидеть полную статью
Поэтому при тестировании генераторов лучше всего думать о них как о циклах, которые выполняются, когда вы им приказываете.
Шаг 1
it(‘should return 6’, () => { // we’ve set up the generator, but we haven’t called next yet so we’re not at a yield const gen = count() expect(gen.next().value).toEqual(call(addNumber, number, 1)) expect(gen.next(1).value).toEqual(call(addNumber, number, 2)) expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) expect(gen.next(6).value).toEqual(put(something(6))) }) function *count() { -> // We haven’t told the generator to exicute anything yet so we’re not at a yield let number = 0 number = yield call(addNumber, number, 1) number = yield call(addNumber, number, 2) //3 number = yield call(addNumber, number, 3) //6 yield.put(something(number)) }
На этом этапе мы еще ничего не сказали генератору, поэтому нам нечего тестировать.
Шаг 2
it(‘should return 6’, () => { const gen = count() // This next is called, we’re seeing what the yield will be expect(gen.next().value).toEqual(call(addNumber, number, 1)) expect(gen.next(1).value).toEqual(call(addNumber, number,2)) expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) expect(gen.next(6).value).toEqual(put(something(6))) }) function *count() { let number = 0 // Generator is paused here, waiting. The yield call(addNumber, number, 1) hasn’t executed -> number = yield call(addNumber, number, 1) number = yield call(addNumber, number, 2) //3 number = yield call(addNumber, number, 3) //6 yield.put(something(number)) }
Здесь мы выполнили gen.next()
. Мы сказали генератору перейти к оператору yield и подождать. Итак, теперь мы остановились на ->
, но на самом деле еще не запустили код.
Когда мы получаем gen.next().value
здесь, мы просто получаем то, что БУДЕТ делать доходность.
Шаг 3
it(‘should return 6’, () => { const gen = count() expect(gen.next().value).toEqual(call(addNumber, number, 1)) // called next here, this evaluated the previous line. We pass in the return value from the last line expect(gen.next(1).value).toEqual(call(addNumber, number, 2)) expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) expect(gen.next(6).value).toEqual(put(something(6))) }) function *count() { let number = 0 number = yield call(addNumber, number, 1) // We evaluated the previous line, now were waiting at the this yield -> number = yield call(addNumber, number, 2) number = yield call(addNumber, number, 3) //6 yield.put(something(number)) }
Здесь мы снова позвонили gen.next()
. Генератор видит эту команду и выполняет yield, на котором он был приостановлен, и продолжает следующий оператор yield. Здесь будет пауза ->
. gen.next()
сообщает оператору yield, в котором он должен был выполняться, мы можем передать то, что мы хотим вернуть, в вызов
Мы были приостановлены на yield call(addNumber, number, 1)
, мы хотели, чтобы он возвращал 1
, поэтому мы передаем это, когда мы действительно выполняем эту строку .
Шаг 4
it(‘should return 6’, () => { const gen = count() expect(gen.next().value).toEqual(call(addNumber, number,1)) expect(gen.next(1).value).toEqual(call(addNumber, number, 2)) // Called next again, we evaluated the call to (number, 2) and specifiy its return value in this next expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) expect(gen.next(6).value).toEqual(put(something(6))) }) function *count() { let number = 0 number = yield call(addNumber, number, 1) number = yield call(addNumber, number, 2) //3 -> number = yield call(addNumber, number,3) //6 yield.put(something(number)) }
Этот шаг похож на предыдущий, просто чтобы проиллюстрировать, о чем я говорю. Выход для call(addNumber, number, 2)
должен возвращать 3
, поэтому мы передаем это в вызов gen.next(3)
, потому что мы сказали генератору выполнить эту строку, и мы хотим, чтобы он возвращал 3
.
Шаг 5
it(‘should return 6’, () => { const gen = count() expect(gen.next().value).toEqual(call(addNumber, number, 1)) expect(gen.next(1).value).toEqual(call(addNumber, number, 2)) expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) // Called next again, we evaluated the call to (number, 3) and specifiy its return value in this next. // I’ve intentionally returned the wrong value from the call to (addNumber, number, 3) to illustrate how the return in next works expect(gen.next(8).value).toEqual(put(something(8))) }) function *count() { let number = 0 number = yield call(addNumber, number, 1) number = yield call(addNumber, number, 2) //3 number = yield call(addNumber, number, 3) //6 -> yield.put(something(number)) }
Мы снова позвонили в gen.next()
, так что теперь ждем доходности до опциона. В этом примере вы можете видеть, что я намеренно вернул неправильное значение «8» в gen.next()
. Это показано, чтобы проиллюстрировать, что next принимает значение, возвращаемое предыдущим выполнением. В данном случае данные только имитируют. Теперь мы видим, что доходность, на которой мы остановились, составляет put(number)
. Поскольку number
в данном случае 8
(потому что это то, что мы сказали call(addNumber, number, 3)
вернуться, это то, что мы ищем.
ШАГ 6
it(‘should return 6’, () => { const gen = count() expect(gen.next().value).toEqual(call(addNumber, number, 1)) expect(gen.next(1).value).toEqual(call(addNumber, number, 2)) expect(gen.next(3).value).toEqual(call(addNumber, number, 3)) expect(gen.next(8).value).toEqual(put(something(8))) // Finally call next again to see there are no more yields expect(gen.next().done).toBeTruthy() }) function *count() { let number = 0 number = yield call(addNumber, number, 1) number = yield call(addNumber, number, 2) //3 number = yield call(addNumber, number, 3) //6 yield.put(something(number)) -> }
Наконец, мы снова вызываем gen.next()
. Поскольку урожаев больше нет, мы можем увидеть, что сага закончена.