Have you ever feel like that extra it
or test
block you've just added inside your describe
test block, looks exactly like the one you wrote before ? 🤔
Recently, while unit-testing one of my latest OSS projects ( @nxrocks/nx-spring-boot: a plugin to generate and integrate a Spring Boot
project inside a Nx
workspace), I asked myself that same question.
My use case
I needed to test that my plugin was working perfectly for the two build systems available for Spring Boot projects (Maven
and Gradle
), as well as for generating either application
or library
projects.
I had already tested the correct generation for Maven-based applications
:
So 3 more combinations remained to be tested:
- Generation of Maven-based
libraries
- Generation of Gradle-based
applications
- and Generation of Gradle-based
libraries
The naive solution: duplicated test blocks
So at first, I copy-pasted that first test to make the others three. The complete test suite was:
It was working fine of course... but felt terribly wrong. The 4 tests are looking almost exactly the same, except for a few parameters that change.
I wasn't comfortable with this duplication as it makes refactoring harder and gives a huge kick in the n**ts🌰 to the DRY principle.
Coming from a Java
background, I was aware of a technique called parameterized testing with Junit
(the most used testing library in Java
), which allows executing a single test method multiple times with different parameters.
That was exactly what was needed here. So I asked myself:
does the same kind of library exist in
Javascript
?
A quick search on Google later, I found what I was looking for: jest-each
A parameterised testing library for Jest inspired by mocha-each.
The optimal solution: parameterized tests!
jest-each
(which is already integrated into the Jasmine's it
/test
/describe
provided by Jest, so no additional installation required) allows you to provide multiple arguments to your test
/describe
blocks, which results in the test/suite being run once per row of parameters.
This is how the previous test suite could be rewritten:
Soooo much better right?! Short and concise 😉.
How does it work?
Let's break it down a little bit:
1 - In the above code block (lines 4-9
), using a tagged template provided by the library, we can express the parameters of our test, in this cool table-like style.
it.each`
projectType | buildSystem | buildFile | wrapperName
${'application'} | ${'maven-project'} | ${'pom.xml'} | ${'mvnw'}
${'application'} | ${'gradle-project'} | ${'build.gradle'} | ${'gradlew'}
${'library'} | ${'maven-project'} | ${'pom.xml'} | ${'mvnw'}
${'library'} | ${'gradle-project'} | ${'build.gradle'} | ${'gradlew'}
`
Note: The first row expresses the parameters, the following rows express the different values they can take
2 - In the test
's (or it
's) description, we can reference the parameters (the headers in the above table) using the syntax $paramName
, which allows a dynamic test description.
3 - We reference the parameters in our test body, by providing them as an object parameter
of our test function ({ projectType, buildSystem, buildFile, wrapperName }
).
("should download a spring boot '$projectType' build with '$buildSystem'", async ({ projectType, buildSystem, buildFile, wrapperName }) => {
// your expectations here...
}
That's it!
Happy Testing! 👩🏾💻👨🏾💻
Top comments (5)
jest in case you didn't notice there is one similar library :)
Hi Mišo,
Thanks for sharing! Different library, but same base idea: parameterized testing!
I personally find jest-each to be more readable through... But hey, opinionated choice!
I guess it will be less tidy, but can't you put
it
calls inside a for-loop?Personally I prefer to use Jest own built-in ‘test.each()’ api for this purpose, as it doesn’t require any additional packages.
Hi Borys,
Thanks for your input! I wasn't aware of the existence of
each()
right from theit/test
objects from Jest Jasmine! Plus, it is exactly the same API! In fact, the feature actually comes fromjest-each
package: github.com/facebook/jest/tree/mast...So no need to install the package separately!
I will update the article accordingly.
Cheers!