如何监视并断言未导出方法?Deno测试场景求助
Deno测试:验证
prepareData执行及返回值的问题 项目结构
├── Readme.md ├── input.json ├── main.ts ├── services │ ├── calculateTransactionTotals.js │ └── validateInput.js └── tests ├── mocks.js └── tests.test.js
相关代码
main.js
import { validateInput, readInputFile } from './services/validateInput.js' import { calculateTransactionTotals } from './services/calculateTransactionTotals.js' validateInput() const content = await readInputFile() calculateTransactionTotals(content)
calculateTransactionTotals.js
import groupby from 'https://esm.sh/lodash.groupby' import moment from 'https://esm.sh/moment' export function calculateTransactionTotals(content) { groupTransactionsByUserAndCurrency(content) // 省略实现,主要是多次groupby操作 prepareData(groupTransactionsByUserAndCurrency(content), content) } function prepareData(transactionsGroupedByUserIdAndCurrency, content) { const result = {} // 此处为业务逻辑 printTable(result) return result } function printTable(result) { console.table(result, ['GBP', 'EUR', 'USD', 'last-activity']) } export const _internals = { prepareData }
当前测试代码(无法生效)
import { calculateTransactionTotals, _internals } from '../services/calculateTransactionTotals.js' import data from './mocks.js' import { assertSpyCalls, spy } from 'https://deno.land/std@0.158.0/testing/mock.ts' Deno.test('is the expected result returned', () => { const prepareDataSpy = spy(_internals, 'prepareData') calculateTransactionTotals(data) assertSpyCalls(prepareDataSpy, 1) })
问题原因
当前spy无法生效,是因为calculateTransactionTotals内部直接调用的是模块内的prepareData函数,而_internals.prepareData只是该函数的一个引用副本——spy拦截的是副本的调用,不会影响模块内部的原函数调用。
解决方案
方案1:重构代码,让依赖可注入
修改calculateTransactionTotals,允许传入自定义的prepareData函数,同时让函数返回处理结果,方便测试断言:
// calculateTransactionTotals.js export function calculateTransactionTotals(content, prepareFn = prepareData) { const groupedData = groupTransactionsByUserAndCurrency(content) return prepareFn(groupedData, content) // 返回处理结果 }
测试时传入mock函数,直接验证调用次数和返回值:
// tests.test.js import { calculateTransactionTotals } from '../services/calculateTransactionTotals.js' import data from './mocks.js' import { assertSpyCalls, spy } from 'https://deno.land/std@0.158.0/testing/mock.ts' import { assertEquals } from 'https://deno.land/std@0.158.0/testing/asserts.ts' Deno.test('prepareData is called once and returns expected value', () => { const mockPrepare = spy((grouped, content) => { // 模拟业务逻辑返回预期结果 return { "user_1": { GBP: 300, EUR: 0, USD: 150, "last-activity": "2024-06-01" } } }) const result = calculateTransactionTotals(data, mockPrepare) assertSpyCalls(mockPrepare, 1) assertEquals(result, { "user_1": { GBP: 300, EUR: 0, USD: 150, "last-activity": "2024-06-01" } }) })
方案2:直接测试calculateTransactionTotals的输出结果
如果不需要验证内部函数调用,只需要确保最终聚合结果正确,可以直接测试函数返回值:
// 先修改calculateTransactionTotals,让它返回prepareData的结果 export function calculateTransactionTotals(content) { const groupedData = groupTransactionsByUserAndCurrency(content) return prepareData(groupedData, content) }
测试代码:
import { calculateTransactionTotals } from '../services/calculateTransactionTotals.js' import data from './mocks.js' import { assertEquals } from 'https://deno.land/std@0.158.0/testing/asserts.ts' Deno.test('returns correct aggregated transaction totals', () => { // 根据mock data定义预期的聚合结果 const expected = { "user_123": { GBP: 500, EUR: 200, USD: 0, "last-activity": "2024-05-20" }, "user_456": { GBP: 0, EUR: 100, USD: 300, "last-activity": "2024-05-25" } } const result = calculateTransactionTotals(data) assertEquals(result, expected) })
方案3:使用mockModule拦截模块内部函数
如果不想修改业务代码,可以用Deno的mockModule来替换模块内的prepareData函数:
import data from './mocks.js' import { assertSpyCalls, spy, mockModule } from 'https://deno.land/std@0.158.0/testing/mock.ts' import { assertEquals } from 'https://deno.land/std@0.158.0/testing/asserts.ts' Deno.test('prepareData is called and returns expected value', async () => { const mockPrepareData = spy(() => ({ test_result: 'valid' })) // 拦截模块,替换内部的prepareData const { calculateTransactionTotals: mockedCalc } = await mockModule( '../services/calculateTransactionTotals.js', (mod) => { mod.prepareData = mockPrepareData } ) const result = mockedCalc(data) assertSpyCalls(mockPrepareData, 1) assertEquals(result, { test_result: 'valid' }) })
内容的提问来源于stack exchange,提问作者George Katsanos
相关产品推荐
相关产品推荐

