Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Clean Code in JavaScript

You're reading from  Clean Code in JavaScript

Product type Book
Published in Jan 2020
Publisher Packt
ISBN-13 9781789957648
Pages 548 pages
Edition 1st Edition
Languages
Concepts
Author (1):
James Padolsey James Padolsey
Profile icon James Padolsey

Table of Contents (26) Chapters

Preface 1. Section 1: What is Clean Code Anyway?
2. Setting the Scene 3. The Tenets of Clean Code 4. The Enemies of Clean Code 5. SOLID and Other Principles 6. Naming Things Is Hard 7. Section 2: JavaScript and Its Bits
8. Primitive and Built-In Types 9. Dynamic Typing 10. Operators 11. Parts of Syntax and Scope 12. Control Flow 13. Section 3: Crafting Abstractions
14. Design Patterns 15. Real-World Challenges 16. Section 4: Testing and Tooling
17. The Landscape of Testing 18. Writing Clean Tests 19. Tools for Cleaner Code 20. Section 5: Collaboration and Making Changes
21. Documenting Your Code 22. Other Peoples' Code 23. Communication and Advocacy 24. Case Study 25. Other Books You May Enjoy

Writing Clean Tests

In the last chapter, we covered the theory and principles underlying software testing. We delved into the benefits and challenges inherent in unit, integration, and E2E testing. In this chapter, we will take this knowledge and apply it to some real-world examples.

It's not sufficient to simply understand what testing is and see its merits from a business perspective. The tests we write form a significant part of our code bases, and should hence be crafted in the same careful manner as all other code we write. We want to craft tests that not only give us confidence that our code works as intended, but are themselves reliable, efficient, maintainable, and usable. We must also be wary of writing overly complex tests. Doing so can trap us in a situation where our tests increase the burden of understanding and lead to more overall complexity and flakiness in...

Testing the right thing

One of the most important considerations when writing any test, whether a granular unit test or a far-reaching E2E test, is the question of what to test. It's entirely possible to test the wrong thing; doing so can give us false confidence in our code. We may write a huge test suite and walk away grinning, thinking that our code now fulfills all expectations and is utterly fault-tolerant. But our test suite may not test the things we think it does. Perhaps it only tests a few narrow use cases, leaving us exposed to many possibilities of breakage. Or perhaps it conducts tests in a way that is never emulated in reality, leading to a situation where our tests don't protect us from failures in production. To protect us against these possibilities, we must understand what we truly wish to test.

Consider a function that we've written to extract...

Writing intuitive assertions

The core of any test is its assertions. An assertion prescribes exactly what we expect to occur, and so it is vital not only that we craft it accurately but that we craft it in a way that our expectation is made utterly clear.

A single test will usually involve several assertions. And a test will typically follow the form of: given an input of X, do I receive an output of Y? Sometimes, establishing Y is complex and may not be constrained to a singular assertion. We may want to introspect Y to confirm that it is truly the desired output.

Consider a function named getActiveUsers(users), which will return only the active users from a set of all users. We may wish to make several assertions about its output:

const activeUsers = getActiveUsers([
{ name: 'Bob', active: false },
{ name: 'Sue', active: true },
{ name: 'Yin&apos...

Creating clear hierarchies

To test any code base, we would likely need to write a large number of assertions. Theoretically, we could have a long list of assertions and nothing else. However, doing this may make it quite difficult to read, write, and analyze the reports of tests. To prevent such confusion, it is common for testing libraries to provide some scaffolding abstractions around assertions. For example, BDD-flavoured libraries such as Jasmine and Jest supply two pieces of scaffolding: the it block and the describe block. These are just functions to which we pass a description and callback, but together, they enable a hierarchical tree of tests that makes it far easier to comprehend what's going on. Testing a sum function using this pattern might be done like so:

// A singular test or "spec":
describe('sum()', () => {
it('adds two numbers...

Providing final clarity

It can be said that the goal of testing is simply to describe what you have done. By describing, you are forced to assert your assumed truths about how something operates. When these assertions are executed, we can then discern whether our descriptions, our assumed truths, correctly reflect reality.

In the act of description, we must choose our words carefully so that they express our meaning clearly and comprehensibly. Tests are one of our last defenses against obscurity and complexity. Some code is unavoidably complicated, and we should ideally craft it in a way that reduces its obscure nature, but if we can't fully do this, then it is the role of tests to clear up any remaining confusion and provide the final point of clarity.

The key to clarity while testing is to focus purely on the perspective of the person who must read through the tests ...

Creating clean directory structures

Our test suites should usually be constrained to individual files, to delineate areas of concern for our programmer-colleagues. Organizing these test files to form a coherent part of a larger code base can be a challenge, though.

Imagine a small JavaScript code base with the following directory structure:

app/
components/
ClockComponent.js
GalleryComponent.js
utilities/
timer.js
urlParser.js

It's quite typical to place tests relating to particular code in sub-directories close to where that code resides. In our example code base, we may create the following tests sub-directories to contain unit tests for our components and utilities:

app/
components/
ClockComponent.js
GalleryComponent.js
tests/
ClockComponent.test.js
GalleryComponent.test.js
utilities/
timer.js
urlParser.js
tests/
timer.test...

Summary

In this chapter, we have applied our theoretical knowledge of testing to the practical craft of constructing real, working, and clean test suites. We looked at some of the pitfalls that exist in doing so, and we highlighted the important qualities to strive for, such as clarity, intuitive naming, and following conventions.

In the next chapter, we will be looking into a variety of tools we can use to help us to write cleaner code, from linters to compilers, and beyond!

lock icon The rest of the chapter is locked
You have been reading a chapter from
Clean Code in JavaScript
Published in: Jan 2020 Publisher: Packt ISBN-13: 9781789957648
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}