Updated: add in context to what the topic is focused on.

How many times have we heard writing test is difficult. There are so many discussions out there that helps us get out of that mentality. This isn’t another one of those. I would assume that you take delight in writing unit test.

We are going to look into a couple ways we can make our test more weathered and durable. Although we will be using Jasmine, these concepts can be used in any JavaScript framework.

Before we continue, I must point out that these test styles are only for situations where a test double is required.

When is a test double not required? I’m for the idea that we shouldn’t create test doubles when it is not expensive. Expensive being that the test touches on layers that are not in arms-reach such as ajax calls, kernel calls, OS interactions or async activities. If it’s a simple service with some algorithm, just use it; why bother when it’s not going to cost you.

Never fake it; stalk the real deal

To be able to test some sort of directive or provider, I tend to see people just faking the injected services.

Don’t do that. Why not?

Dealing with a dynamic scripting language, you don’t get the benefit of interface and real-time errors (unless you’re using TypeScript this may not apply to you).

If ever your interface of your dependencies change, you’re not going to find out, because your code is testing against a make-believe friend who’s got your back even when both of you are failing.

A better way is to inject the same service into your test and spy on it.

Spy on actual instances

What benefits do you get?

More resilient test A contract test — ensure everyone is quacking correctly An “integration” test on a unit level — cheap! Have more confidence with what you wrote Bonus — you can run through actual logic if you want

So here’s an example of when you may have changed the service’s interface but forgot to update another code that’s using it

Never mock what you don’t own

“Writing unit test is hard” is something you might have heard when dealing with dependencies that you didn’t write (IE. 3rd party libraries). That’s because we’re trying to mock something we don’t own!

Note: as I mentioned at the start, you’d still want to mock or fake a 3rd libraries if it is expensive.

There are a few reasons I don’t mock 3rd party libs. I just use the real deal. Here few reasons:

The code doesn’t belong to you, if the library didn’t adhere to SemVer, you’ve updated it, your test is still going to pass but not your code. You’ve made the responsibility to rely on it. You know the expected outcome. Rely on it the same way in your test. Trying to mock it may lead to an output that could be wrongly assumed.

Digressing slightly, I might have taken this slightly out of context. Ideally you’d want to use an adapter pattern to wrap the logic so you can better stub it. But sometimes the input and output is so trivial, writing that extra abstraction could be redundant code.

So coming back to my point, just use the actual implementation when it’s code abstracted away from you.

Conclusion

These aren’t rules. They are just some methodologies you could use to make JS test more resilient. Of course there are better ways of dealing with them; such as using TypeScript and the adapter pattern.

I guess what I want to convey, is testing should let you sleep soundly at night. Who cares if it goes against the grain. Do what makes it more resilient to uncaught changes and unmet errors. As long as you’re getting true positives and confidence in your code, do it!