神刀安全网

How function spies work in JavaScript

If you write unit tests, then you likely use a testing framework and might have come across spies. If you don’t write unit tests, please take a quick pause and promise yourself to always write tests.

Testing framework suggestions? Try Sinon or Jasmine .

Spies allow you to monitor a function; they expose options to track invocation counts, arguments and return values. This enables you to write tests to verify function behaviour.

They can even help you mock out unneeded functions. For example, dummy spies can be used to swap out AJAX calls with preset promise values.

The code below shows how to spy on the bar method of object  foo.

spyOn(foo, 'bar'); foo.bar(1);  expect(foo.bar).toHaveBeenCalled(); expect(foo.bar).toHaveBeenCalledWith(1);

Jump into the documentation for more examples.

That was pretty cool right. So how difficult can it be to write a spy and what happens under the hood?  It turns out implementing a spy is very easy in JavaScript. So let’s write ours!

The goal of the spy is to intercept calls to a specified function. A possible approach is to replace the original function with another function that stores necessary information and then invokes the original method.Partial application makes this quite easy…

The Code

function Spy(obj, method) {     let spy = {         count: 0,         args: []     };      let original = obj[method];     obj[method] = function() {         let args = [].slice.call(arguments);         spy.count++;         spy.args.push(args);         return original.call(obj, args);     };      return spy; }  let sample = {     fn: function(args){         console.log(args);     } };  let spy = Spy(sample, 'fn'); sample.fn(1,2,3); console.log(b.count); //1 console.log(b.args); //[[1,2,3]]  sample.fn('The second call'); console.log(b.count); //2 console.log(b.args); //[[1,2,3], 'The second call']

Taking the code apart

The spy method takes an object and a method to be spied upon. Next, it creates an object containing the call count and an array tracking invocation arguments.

Finally, it swaps out the original call with a new function that always updates the information object whenever the original method is invoked.

Limitations

The toy sample is brittle (yes I know it). Can you spot the issues? Here are some:

  • What happens if the method doesn’t exist on the object?
  • What happens if the object is null?
  • Can it work for non-object methods? Would pure functions work? Would using window as the parent object work?
  • What happens if method is a primitive and not a function?

These can (and should) be fixed but again, that would make this post very complicated. The goal was to show a simple toy implementation.

Challenges

How do you ‘unregister’  spies without losing the original method? Hint: store it in some closure and replace once you expose an unregister call.

How would you implement a spy in Java?

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » How function spies work in JavaScript

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮