Nested Unit Tests: An Anti-Pattern - a podcast by Kent C. Dodds

from 2016-05-25T15:57:03

:: ::

At first I was really bothered that AVA (http://npm.im/ava) didn't have support for nested tests, but now I consider nesting tests to be an anti-pattern.
Here's an example of the kind of thing I mean (see this in a syntax-highlighted gist here (https://gist.github.com/kentcdodds/576c16d2069b3535aa4d7435082b186a)):
Mocha with nesting (don't mind the actual tests, just imagine what this would be like with a larger test file):
```javascriptimport Customers from'./Customers'import getMockCustomers from'./Customers/mocks'describe('Customers', () =>{
let mockCustomersbeforeEach(() =>{
Customers.setCustomers([]) // initialize to empty for most tests
mockCustomers = getMockCustomers() // have mock customers available})
afterEach(() =>{
Customers.setCustomers([]) // clean up just in case
})describe('getCustomers', () =>{
beforeEach(() =>{
Customers.setCustomers(mockCustomers)})
it('should return the existing customers', () =>{
const customers = Customers.getCustomers()expect(customers).to.be.eql(mockCustomers)
// questions you must ask if you're not familiar with this file and
it's bigger:
// - where does mockCustomers come from?// - what make getCustomers return the mockCustomers?
})})
describe('setCustomers', () =>{
it('should set the customers array', () =>{
Customers.setCustomers(mockCustomers)const customers = Customers.getCustomers()
expect(customers).to.be.eql(mockCustomers)// question you must ask if you're not familiar with this file and
it's bigger:
// - where does mockCustomers come from? What is it initialized as?})
})})
```Here's what it would look like without nesting (with AVA, though you could
mostly do this with Mocha too):```javascript
import test from'ava'test('getCustomers: should return the existing customers', t =>{
const mockCustomers = initializeCustomers()const customers = Customers.getCustomers()
t.deepEqual(customers, mockCustomers)cleanupCustomers()
})test('setCustomers: should set the customers array', t =>{
initializeCustomers([])
const mockCustomers = getMockCustomers()Customers.setCustomers(mockCustomers)
const customers = Customers.getCustomers()t.deepEqual(customers, mockCustomers)
cleanupCustomers()})
function initializeCustomers(initialCustomers = getMockCustomers()) {Customers.setCustomers(initialCustomers)
return initialCustomers}
function cleanupCustomers() {Customers.setCustomers([])}
```Like I said, this may be a bad example. Don't be distracted by the tests
themselves. Just look at the it blocks above in the Mocha tests andcompare it to the test block in the AVA tests below. The difference is
that with the it blocks, you have to keep in your head what's going on in
a beforeEach and that relationship is implicit. In the test block,there is a level of abstraction, but it's explicit so you don't need to
worry about keeping it in your head because it's in front of your face.
I hope this is helpful!

Further episodes of 3 Minutes with Kent

Further podcasts by Kent C. Dodds

Website of Kent C. Dodds