correcting unmocked jest functions

실리콘·2023년 2월 20일
0

Problem

function mocking using jest fails

description

file A - class Scanner has Scanner.useScan() method, that uses scan() from fileB, but is not injected as parameted, and used using import.
file B - has export const scan = () => {}// omit arrow function
test T - tests Scanner class from file A, including useScan()

in T, scan is imported using import {scan} from './B'
then mocked using jest

// T.spec.ts
jest.mock('./B', () => ({
  scan : jest.fn()
})

however, original function from file B, not the mocked function, is used when testing. This is because we can't DI scan() function at test file, and is instead imported from file A.

// A.ts
import {scan} from './B'

Reason

import {scan} from './B'
and
import * as scanModule from './B'
has different internal workings.
first one imports only the function to a variable. So if we mock it, it will stay inside current context.
However, second one imports the entire module as an object. So if we mock it, the mocked module will be use even if it is used in a different file.

Solution

1. Use Dependency Injection (IMO Best Practice)

If useScan() takes scan() as argument,

// A.ts
// import {scan} from './B'
class Scanner {
  ////
  useScan(scanFunc: scanFuncType){
   ////
    scanFunc() // omit detai;s
  }

we can use mocked version of scan() as argument for useScan() instead of actualscan() in test file

2. mock the entire module in test file

do either

  • import entire module and mock the functions you want.
// T.spec.ts
import * as ScanModule from './B'

jest.mock('./B', ()=>({
 scan: jest.fn() 
  }))
      
  • mock the module before importing function (not verified)
// T.spec.ts
jest.mock('/B')
import {scan} from './B'

then test

// T.spec.ts
describe('useScanner', () =>{
	testScanner.useScan() // now uses mocked version of `scan()`
	expect(scan).toHaveBeenCalled() // `scan` name can vary
})
profile
software engineer

0개의 댓글