jhnns / rewire

Easy monkey-patching for node.js unit tests
MIT License
3.08k stars 128 forks source link

Injected mocks add functionality rather than replace it #182

Open vileppanen opened 4 years ago

vileppanen commented 4 years ago

Stumbled across a scenario, where I had passing tests written for a function with seemingly working mocks to ensure the function works correctly.

Afterwards, I was starting to refactor the mocked functionality into separate modules, and for clarity, ran the tests at time when the mocked functions would not exist anymore in the tested module. I was expecting the test that verified the mocked function was called to fail due to the function being undefined, but was surprised that the test actually passed.

Investigated how things work when using __with__ (I assume set works kinda similar way) to provide mocked functionality, and it seems to indeed inject the exact mock functionality into tested module, even though it is not part of the real implementation.

Ie. if you provide a mock function in test, and forget to require the same function in the tested module before calling it --> test verifying the mock was called will pass.

I had issues to setup a lean Codesandbox demo for this, so had to rely on separate dummy repo with demonstrating unit test. So in order to reproduce:

  1. Clone https://github.com/vileppanen/rewire-sandbox
  2. Install deps: npm ci
  3. Run npm test
  4. Ensure, that the single unit test will pass, even though it should throw error from the undefined bar function.

Dunno if rewire is supposed to work this way, but for me from mocking perspective, this seems like a huge pitfall, when refactoring code and relying on unit tests to verify things do not break unexpectedly. Before running into this, I was assuming rewire would search for keys that do exist in the tested module and replace them, instead of really injecting new functionality into tested module.

vileppanen commented 4 years ago

Out of curiosity, created this micro-library, which provides a wrapper around rewire to expose __replaceWith__ function that calls the actual __with__ function, after it has removed the mocked entities that do not exist in the tested module. Whether this same behavior would be implemented in the rewire module, I'd gladly hear in order to deprecate the micro-lib project.