Как протестировать функциональную композицию с побочными эффектами без использования насмешек?

#javascript #testing #functional-programming

Вопрос:

У меня есть функция MyComposedFunction , которая представляет собой функциональную композицию из 3 функций , вторая функция fn2 , выполняет запрос POST (побочный эффект), используя результат fn1 и передает это значение fn3 .

 const fn2 = async (fn1Result) => {
    const result = await fetch(fn1Result.url, fn1Result.payload);

    // some business logic

   return fn2Results;
};

const MyComposedFunction = compose(fn3, fn2, fn1);

// My Test
expect(MyComposedFunction('hello world')).toBe('expected result');
 

Я бы хотел избежать написания модульных тестов для fn3 , fn2 , и fn1 и вместо этого только для тестирования MyComposedFunction . Мое обоснование состоит в том, что не должно иметь значения, MyComposedFunction используется compose(...) или является одной длинной гигантской функцией, пока MyComposedFunction она работает.

Можно ли написать тест MyComposedFunction без необходимости издеваться fn2 ?

Я бы подумал, что это, должно быть, относительно распространенная ситуация, когда вы пытаетесь выполнять функциональное программирование на JavaScript, но до сих пор не смогли найти полезный ресурс.

Комментарии:

1. Важным аспектом FP является отделение чистого кода от нечистого и попытка оставить как можно больше кода чистым. Обычно вы достигаете этой цели, откладывая оценку эффектов как можно дольше (например, с приложениями/монадами). Теперь вы можете протестировать обе части по отдельности, но вам все равно нужны насмешки над нечистой.

Ответ №1:

Вы можете ввести fetch в свою функцию, например, так

 const fn2Thunk = (fetcher = fetch) => async (fn1Result) => {
    const result = await fetcher(fn1Result.url, fn1Result.payload);

    // some business logic

   return fn2Results;
};

const fetchMock = async () => ({ result: "blah" })
const MyComposedFunctionTest = compose(fn3, fn2Thunk(fetchMock), fn1);

// My Test
const result = await MyComposedFunctionTest('hello world')
expect(result).toBe('expected result');