Chapter 5. Writing Efficient and Useful Unit Tests

Unit testing is the single most important skill an application developer can master. Sadly, writing unit tests is rarely seen as exciting, let alone important. This chapter will focus on testing various Apex components. We will discuss what to test, when to write the tests, and most importantly, how to test. We will cover the following topics:

  • Why do we write unit tests?
  • What to test—discussing positive, negative, and role-based testing
  • When do we write unit tests?
  • How do we structure tests for speed and code reuse?
  • Mocking
  • Tips and tricks for efficient testing

Why do we write unit tests?

Often, it seems that the answer to why do we write unit tests is because Salesforce makes us do it! This, however, is not the reason we should be writing unit tests. All classes in production orgs have to have 75% code coverage and all triggers must have some coverage. Salesforce enforces this for a number of reasons. As the platform evolves and new features are added, Salesforce needs to ensure that your applications will continue to run without an issue. To do this, they employ the hammer, a specialized test harness that allows them to run every unit test in every org twice. First, the hammer runs every test in every org on the current version of the platform. These same tests are then run on the pre-release version of the platform. This helps them ensure that your code not only runs on the new version of the platform, but that it also runs at least as efficiently as it did on the earlier platforms. Even if your unit tests have no assertions and utterly fail to do anything but run code, the hammer's execution of your tests provides valuable insight into the backward compatibility and efficiency of the platform. This illustrates an important point. Contrary to popular belief, the true cost of software is not in development but in maintenance. The Apex software on the Salesforce1 platform is no exception. While there are upfront development costs, the true cost of the software adds up as after months and years after the initial implementation, developers try to add features, fix bugs, or change the implementation of objects and functions. Without hammer and the unit tests it runs, the cost of upgrading the Salesforce platform would be astronomical! Not only for Salesforce, but for every client running code on the platform. With that in mind, let's look at some concrete positive reasons for writing unit tests.

Proving functionality

The classic reason for unit testing is to prove that the code works as you believe it does. Given an addition method accepting two integer numbers we can assert the output of the method when we know the input. Proving the functionality of our code is the foundation of our testing philosophy because it gives us assurance not only that our code's architecture, engineering, and logic are correct, but also that we understand how that code interacts within the greater system.

Reducing the cost of change

As a system evolves, features are added, deprecated, and changed. It's relatively easy for knowledgeable developers to add features. However, it's difficult to safely deprecate features. The highest risk to a system, however, comes from changing the implementation of the given features. This is where unit tests can save vast amounts of time. Imagine being tasked with replacing the implementation of a complex calculateIncomeTax method. The current implementation and the new implementation are functionally identical, but your new method is 5x faster. Because both implementations are expected to function identically existing tests are valid proofs of functionality for both implementations. Because of this, replacing the implementation of a complex method becomes safer and easier. Make a change to the implementation, and so long as the tests pass, you can be confident you've not introduced a bug.

Encouraging modular, reusable code

As you start to write unit tests for your code, you'll quickly learn that poorly designed, tightly coupled code is difficult to test. Writing tests to ensure software quality and maintainability, rather than to meet deployment requirements, will force certain design choices on your code. You'll end up with code that is more loosely coupled, with less reliance on state, and is generally simpler. Such code is easier to test, and is therefore easier to functionally prove. Additionally, because it no longer requires maintaining state or tightly coupled relationships with other objects, this type of code is almost always reusable code, which is never a bad thing.

Identifying engineering bugs you didn't write

If you're writing software for a living, you're working to solve complex real-world problems, not to prove your understanding of computer science principles. The situations and problems you're tasked with solving are not simple problems, but nuanced, intricate problems complex enough to justify custom software. This can lead to seemingly crazy bugs that are incredibly hard to solve. There are situations where your code fails because of some other bit of code that fails only on the last day of the month or at midnight on Thursdays. I call these Cinderella bugs because they only happen at midnight on the night of the ball. Writing unit tests help you identify these situations before you experience them in production. Granted, you'll need to show some creativity when writing your tests, but learning to test your billing code at midnight on Thursdays is generally the kind of lesson you only need to learn once.

Documenting expected behavior

It's a truism that the job you have now is likely not your first, nor your last. Inevitably we will face the daunting task of learning a new code base. On top of that, outside of a computer science textbook, when have any of us ever encountered a code base that consistently followed best practices as well as proper and sensible object oriented abstractions? Indeed. When I was working as a consultant, coming up to speed on a org's code base was a weekly chore. One of the best ways I've ever found to get up to speed is to read through the tests. Well written tests demonstrate not only what the code does but also what kinds of data are expected and required for that code to run. Fantastic tests will even walk you through failure scenarios and their causes. Even badly written tests give insight into what the developer was thinking the code should do.

Tests + code = less likely to produce bugs

Even if you only write basic unit tests to prove your code functions as you expect, you've decreased the chances of having bugs in your code. Why? There are a few reasons, but the basic principle is that you're less likely to make a logic mistake in two places than you are in one place. With each test you write, you're decreasing the risk that you've got a logic bug somewhere in the code you are testing. Writing good tests helps by not only exercising your code, but also by helping you think through your code's interaction with the greater system. This is especially true if you write your test code first! Forcing yourself and your team to design new functionality up front causes you to pause and consider what existing code you can reuse as well as consider the impact this functionality has on the greater system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.181.57