CodeLive: Positive and Negative Unit Testing

In this stream, Melissa Mueller and I tackled the process of adding positive and negative unit tests for a trigger handler class. Missed the stream? That’s OK! The recording is up and can be found here. (Scroll to the very bottom).

Our mission was to demonstrate testing best practices for two types of unit tests: positive and negative tests. Positive tests are tests that demonstrate that the tested code functions as expected when it’s executed with known, well-formatted parameters. Negative tests, on the other hand, demonstrate that your code properly handles unexpected, malformed or invalid input. We’ve created handy illustrations demonstrating the steps each of these patterns requires.

Positive tests look like this:

The negative test pattern looks like this:

Astute readers will note that the big difference between the two is the addition of a Try/Catch block in the negative test. Because we’re intentionally writing the test to force an exception to occur, we need to catch that exception, or our test will fail!

Melissa and I worked on this codebase, and you can look in on the tests we created here. In the process of writing these tests we (re)learned a top tip: When testing triggers, exceptions thrown by your code are rolled up into higher-level exceptions. This means that even though your code is throwing, say, ‘ContactHandlerException‘, the exception type reported back to the test is a DMLException. However, the getMessage() method will include the custom message you specify, so don’t forget to set that!

Test data is critical to a successful implementation of either of these patterns. Melissa and I chose to use a combination of a TestFactory and an @testSetup method. All of our tests required an Account to exist in the database, so we put Account generation in a @testSetup method. Methods annotated with @testSetup are executed such that each of your individual tests has a new, clean copy of the data before that test method runs. Because we are testing what happens when a Contact is inserted, we couldn’t create the contact in the @testSetup method. Instead, we used a testFactory (we used this one) to generate Contact records for us to insert. I like the test data factories for their consistent interface, regardless of the object being created, and their flexibility. Generally speaking, your test factory should be able to create and insert an object in a single line of code. That makes your tests easy to read and follow!

We’re taking the month of September off to prepare for #Codetober, a whole month of weekly CodeLive streams. We kick back off on October 3 with Kevin O’Hara and we’ll be working with Lightning Web Components Open Source to build an externally hosted dashboard showing information from our Salesforce org! Stay tuned to the Developer Events calendar for exact dates and times — and, of course, to register!