Outline

This is from a tweet which you can find here.

Previous Posts:
  1. Mock Types,
  2. The AAA Structure
  3. Interaction vs State Testing

DRY (don't repeat yourself) is probably the first best practice most people learn about coding. It's probably the most ubiquitous best practice. It's so ingrained in our coding, it's also probably the biggest sin other developers will point out in code.

So when you write unit tests, the idea just seems natural to pursue. But unit tests are much different than production code. The unique environment of unit tests means that the typic rules just don't apply the same way.

So in unit tests, we don't make our code DRY. we make it DAMP. There's some acronym for damp that someone made up. I personally hate it and don't think it conveys the correct information about being DAMP.

So I just teach people that DAMP means that you're not QUITE dry. You're not wet, but you're...damp. So that means that you will see a bit more duplication in unit tests than in production code and that's desirable.

Here's an example. (ignore the poor test names)

it('test removeLastItem', () => {
    cart.addItem(newItem)
    cart.removeLastItem()
    expect(cart.quantity).toBe(0)
})

it('test clear', () => {
    cart.addItem(newItem)
    cart.clear()
    expect(cart.quanity).toBe(0)
})

In that example, there's lots of duplication between the two tests. This is desirable. The duplication allows each tests to not only be independent, but also reduces the possibility of introducing a bug as we naturally try to refactor and remove duplication.

The duplication makes the tests simple and easy to read. It makes the tests easy to change as the code may change. And we don't have an over-abundance of common methods that do things we don't understand.

It's tempting to look at this and think that we should if nothing else move the first line of each test to a common beforeEach method like so

beforeEach(() => {
  cart.addItem(newItem);
})

But this is actually bad. This leaves the tests looking like this:

it('test clear', () => {
    cart.clear()
    expect(cart.quanity).toBe(0)
})

This doesn't tell us what the test is really doing. Looking back to using the AAA structure (see this thread for more info on the AAA structure)

We don't have our Arrange. Sure, it's in the beforeEach, but what if the beforeEach isn't visible on the screen currently?

That isn't to say that we don't use beforeEach to do setup, but we need to put important setup INSIDE the test. And letting ourselves duplicate code sometimes, and make our tests DAMP enables this. More on what setup should be inside the test, and what shouldn't in a later tweet.

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.

 

I finished! On to the next chapter