1
\$\begingroup\$

I have been making an effort to add a fair amount of unit testing into my code. However, I find myself going against the DRY principle quite a bit.

I am currently running tests on my API with my tests in the following folder structure:

/user
 user.model.js
 user.test.js
 ....
/blog
 blog.model.js
 blog.test.js
....

Ive been using wildcards in my script test path to target all my test files nodemon --exec 'mocha ../api/resources/**/*.test.js'

I have noticed all my test files have a lot of stuff to require. Most of which is the same in each of the test files, example:

const chai = require('chai')
const chaiHttp = require('chai-http')
const { expect } = chai
const app = require('../../../app')
const { dropDb } = require('../../../test/helpers')
const mongoose = require('mongoose')
const User = mongoose.model('user')
chai.use(chaiHttp)

And my tests have a lot of duplicate 'expect' statements

it('should return error when no user email found', async () => {
 const result = await chai.request(app)
 .post('/api/user/login')
 .send({ email: '[email protected]', password: currentUserData.password })
 *expect(result).to.have.status(401)
 expect(result.error).to.exist
 expect(result.error.text).to.contain('No user found')*
})
it('should return error when password is incorrect', async () => {
 const result = await chai.request(app)
 .post('/api/user/login')
 .send({ email: currentUserData.email, password: '123456' })
 *expect(result).to.have.status(401)
 expect(result.error).to.exist
 expect(result.error.text).to.contain('Incorrect password')*
})

As you can see from the above tests the expect statements are basically the same minus the text. I have a lot of other tests where I have expects that check to make sure its JSON data or 200 before the more specific expects.

To me it feels as if I am repeating myself quite a bit on the requires and the expect statements. Is this standard practice or could I create some sort of higher order function to run the tests without having to require all the time.

Additionally, can I reuse a function with similar expect statements in it?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 10, 2018 at 22:21
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

One of the recommended techniques for tests is refactor into an assert method. Duplications drive into fragile tests.

You should also try to create factory methods for the SUT.

it('should return error when password is incorrect', async () => {
 // Arrange
 const aValidEmail = currentUserData.email
 const aWrongPassword = '123456'
 // Act
 const result = await makeLoginRequest(aValidEmail, aWrongPassword)
 // Assert
 expectErrorResult(401, 'Incorrect password')
})

EDIT: In the end, makeLoginRequest() is not a factory method, but it could be the equivalent for this type of SUT. What we are trying to achieve here is avoiding the need to modify the test when the SUT modifies its interface (like the endpoint or adding/removing unrelated parameters)

answered Aug 11, 2018 at 12:45
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.