Outline
This is from a tweet which you can find here
Previous Posts:
- Mock Types,
- The AAA Structure
- Interaction vs State Testing
- DAMP vs DRY
- Thinking from the Client's Perspective
- The 10 Aspects of a Good Test
Use only 1 logical assertion
When writing a unit test, make sure you only use one logical assert/expectation. (which is different from 1 physical assertion)
A unit test isn't a unit test unless you assert/expect something, such as a return value being 10, or a cart to be empty, etc. Using the AAA structure (see previous post) the assert comes last. This tests that things are the way we expect.
Often times a specific state change can cause multiple results. This usually isn't true when we test the output of a call. But it is often true when we check to see that the correct changes were made.
For example, If you add an item to a cart with 3 items, it may cause the following changes: 1. the cart now has 4 items 2. An internal-only "favorite" list is updated to show that this user really must be interested in this item 3. The item is put on hold in inventory for 10 mins
If you write a unit test that adds this 4th item to a cart, you SHOULD NOT test all 3 resulting conditions.
expect(cart.length).toBe(4);
expect(user.favorites).toContain(item);
expect(inventory.onHold).toContain(item);
This is a poor unit test. This test now tests too many things. If your test fails, it may not be immediately obvious which functionality is broke. Is it the cart management code? Is it the favorites? is it the inventory? Those things should all be tested separately.
it('should add an item to the card')
it('should add an item to favorites')
it('should put inventory on hold')
3 separate tests.
But you may require multiple PHYSICAL assertions to assert one logical condition.
For example, to know that an item was removed properly from a cart, you MIGHT see the following code
cart.remove(item);
expect(cart.itemCount).toBe(3)
This isn't sufficient. We only are testing that something got removed. Did it remove the correct item? We may need more expect statements.
cart.remove(item);
expect(cart.itemCount).toBe(3);
expect(cart.items).not.toContain(item);
Now we are successfully testing that the item got removed.
This is two physical assertions, but really only one logical assertion.
So make sure your unit tests contain only one logical assertion.
Discounted Courses
Here at Thinkster, we use educational science to teach you five times faster than you would learn the same topics elsewhere. By joining as a Pro subscriber you have access to our complete library on courses on Angular, React, Vue, JavaScript, and More.
To help you get started, use this link for a discount on a monthly membership.
Or save even more with an annual membership.