Decorate the @decorator to exclude in unit testing

One side effect of using decorators is that a decorator will run when running unit tests run against the [decorated] function. I wanted a way to signal that a decorator should be ignored (ie, should not apply itself to the underlying function) for a certain condition (where, the condition in this case is if we’re in a unit testing context).

I’m sure we could have a debate about whether this is a good thing or not, but in this case, the decorator was doing cross-cutting work that wasn’t directly related to the unit under test, so I wanted to test each in isolation.

My decorator was a stand-alone function [originally] and decorator syntax isn’t directly supported on stand-alone functions (only functions on object literals or methods of a class). So initially I wrapped my decorator in a function which would precede the decorator function at runtime and achieve my goal. So here’s essentially what that looked like:


const decoratorWrapper = (decorator) => {
return (target, key, descriptor) => {
descriptor.value = function (target, key, descriptor) {
if (window.jasmine) {
return descriptor;
}
return decorator(target, key, descriptor);
};
return descriptor;
};
};
const myDecorator function () {
// Here we're wrapping our decorator essentially in another decorator
return decoratorWrapper((target, key, descriptor) => {
const originalFunction = descriptor.value;
descriptor.value = async function () {
// do stuff before the decorated function
result = await originalFunction.apply(this, arguments);
// do stuff after the decorated function
return result;
};
return descriptor;
});
}

So while that worked, I wasn’t thrilled because I was essentially running a decorator-like function imperatively with too much ceremony. So then I looked at putting my decorator in an object literal (to satisfy the decorator syntax which doesn’t support stand-alone function decorators directly)  but then the descriptor takes on a slightly different shape, with an initializer property replacing the value property. Anyhow, I’m not thrilled syntactically with this but here’s the decorate-the-decorator approach, whereby our wrapper becomes a true decorator (in it’s own module), and our custom decorator just had to be tweaked a tiny bit into ES6 class syntax and to break up the decorator factory from the actual decorator function itself. We’re still able to construct the decorator class, then export the decorator function, such that consumers will never know about the weird syntax implementation in the decorator. Here’s what that looks like:


// ignoreDuringUnitTestDecorator.js
const ignoreDuringUnitTest () => (target, key, descriptor) => {
const originalFunction = descriptor.value;
descriptor.value = function (target, key, descriptor) {
if (window.jasmine) {
return descriptor;
}
return originalFunction(target, key, descriptor);
};
return descriptor;
};
// myCustomDecorator.js
class MyCustomDecorator {
constructor() {
this.decoratorFactory = this.decoratorFactory.bind(this);
}
@ignoreDuringUnitTest()
decorator(target, key, descriptor) {
const originalFunction = descriptor.value;
descriptor.value = async function () {
// do stuff before decorated function
result = await originalFunction.apply(this, arguments);
// do stuff before decorated function
return result;
};
return descriptor;
}
decoratorFactory() {
return this.decorator;
}
}
// Exporting as a default means consuming modules can import your decorator in a typical fashion
// without being aware of the weirdness of the class approach in here.
export default new VerifyWorkflowState().decoratorFactory;

And then we can decorate any function in a module as:


import myCustomDecorator from "./myCustomDecorator";
class Whatever {
@myCustomDecorator
myFunction(){
//….
}
}

And the decorator will run normally when run outside our jasmine unit testing context or will be skipped if so.

NOTE: I did add a tiny bit extra (not shown) to allow this exclusion to be temporarily paused so I could actually unit test the decorator itself too 🙂

Mocking with Moq and Moles

I had the pleasure recently to do some unit testing work for some foundational classes (not, not TDD, but still…) and decided to quit stubbing and start Mocking.  One of our colleagues recommended Moq, and that’s the one we went with.  Moq is great, and I totally dig the mocking approach and am astonished yet again at how little I’ve actually known about real unit testing.  One little problem I ran into with Moq, however, led me to another little gem (Hint: Moles).  See, I was unit testing already-existing classes, and the idea of refactoring to make them more unit test friendly was not part of the plan.  Luckily nearly all the classes either directly supported dependency injection, so getting around dependencies in most cases was quite straight forward.  However, there were a few scenarios where I needed to mock out non-virtual methods, or, gasp, static routines.  Turns out Moq does not excel in this department, so I stumbled upon the awesomeness of Microsoft Moles.  Moles fit right into my scenario allowing me to swap out non-virtual and/or static routines that were inherent dependencies in the execution path of the routines I was unit testing.  For example, if you are writing a unit test for the routine “Foo” and within that routine, there is a call to a static method that actually *does* something outside the scope of the unit test (ie, *it* has dependencies on something), then you can use Moles to basically swap out that routine (essentially hijack it and force that code to use whatever you tell it to use – perhaps replacing the static method with a do-nothing routine).

So, if you are unit testing, or perhaps even new to unit testing, I encourage you to consider looking at both of these tools.  Perhaps start out with Moq, but if you encounter the same limitation, check out Moles.

J